diff --git a/pom.xml b/pom.xml
index f9f41c8..480c672 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
de.srsoftware
web4rail
- 0.9.18
+ 0.9.19
Web4Rail
jar
Java Model Railway Control
diff --git a/src/main/java/de/srsoftware/web4rail/Plan.java b/src/main/java/de/srsoftware/web4rail/Plan.java
index 2c1f599..54abd10 100644
--- a/src/main/java/de/srsoftware/web4rail/Plan.java
+++ b/src/main/java/de/srsoftware/web4rail/Plan.java
@@ -550,8 +550,12 @@ public class Plan implements Constants{
* @return
* @throws IOException
*/
- public Tile place(Tile tile) throws IOException {
- stream("place "+tile.tag(null));
+ public Tile place(Tile tile) {
+ try {
+ stream("place "+tile.tag(null));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
return tile;
}
diff --git a/src/main/java/de/srsoftware/web4rail/Route.java b/src/main/java/de/srsoftware/web4rail/Route.java
index a5c7964..4097933 100644
--- a/src/main/java/de/srsoftware/web4rail/Route.java
+++ b/src/main/java/de/srsoftware/web4rail/Route.java
@@ -26,7 +26,7 @@ import de.srsoftware.web4rail.actions.Action.Context;
import de.srsoftware.web4rail.actions.ActionList;
import de.srsoftware.web4rail.actions.ActivateRoute;
import de.srsoftware.web4rail.actions.FinishRoute;
-import de.srsoftware.web4rail.actions.FreeStartBlock;
+import de.srsoftware.web4rail.actions.FreePreviousBlocks;
import de.srsoftware.web4rail.actions.SetSignalsToStop;
import de.srsoftware.web4rail.actions.SetSpeed;
import de.srsoftware.web4rail.conditions.Condition;
@@ -43,7 +43,6 @@ import de.srsoftware.web4rail.tiles.Signal;
import de.srsoftware.web4rail.tiles.Tile;
import de.srsoftware.web4rail.tiles.Turnout;
import de.srsoftware.web4rail.tiles.Turnout.State;
-
/**
* A route is a vector of tiles that leads from one block to another.
*
@@ -131,8 +130,12 @@ public class Route implements Constants{
* @throws IOException
*/
public void activate() throws IOException {
- LOG.debug("{} aktiviert.",this);
- for (Tile tile : path) tile.train(train);
+ for (Tile tile : path) {
+ if (!(tile instanceof Block)) tile.train(train);
+ }
+ train.heading(endDirection.inverse());
+ endBlock.train(train);
+ startBlock.trailingTrain(train);
}
/**
@@ -301,8 +304,8 @@ public class Route implements Constants{
if (!contacts.isEmpty()) {
Contact lastContact = contacts.lastElement();
add(lastContact.trigger(), new SetSpeed());
- add(lastContact.trigger(), new FreeStartBlock());
add(lastContact.trigger(), new FinishRoute());
+ add(lastContact.trigger(), new FreePreviousBlocks());
}
}
@@ -331,16 +334,14 @@ public class Route implements Constants{
return endBlock;
}
- public void finish() throws IOException {
- train.route = null;
- unlock();
- endBlock.train(train.heading(endDirection.inverse()));
- train = null;
+ public void finish() {
+ reset();
+ train.block(endBlock, false);
+ train.heading(endDirection.inverse());
}
-
- public void fireSetupActions(Context context) {
- setupActions.fire(context);
+ public boolean fireSetupActions(Context context) {
+ return setupActions.fire(context);
}
public boolean free() {
@@ -350,11 +351,6 @@ public class Route implements Constants{
return true;
}
- public Route freeStartBlock() throws IOException {
- startBlock.train(null);
- return this;
- }
-
private String generateName() {
StringBuilder sb = new StringBuilder();
for (int i=0; i lockedTiles = new ArrayList();
try {
for (Tile tile : path) lockedTiles.add(tile.lock(this));
- } catch (IOException e) {
- for (Tile tile: lockedTiles) try {
- tile.unlock();
- } catch (IOException inner) {
- LOG.warn("Was not able to unlock {}!",tile,inner);
- }
+ } catch (IllegalStateException e) {
+ for (Tile tile: lockedTiles) tile.unlock();
return false;
}
return true;
@@ -541,6 +533,18 @@ public class Route implements Constants{
return win;
}
+ public void reset() {
+ new SetSignalsToStop().fire(new Context(this));
+ for (Tile tile : path) {
+ if (!(tile instanceof Block)) tile.unlock();
+ }
+ if (endBlock.route() == this) endBlock.lock(null);
+ if (startBlock.route() == this) startBlock.lock(null);
+ train.heading(startDirection);
+ train.block(startBlock, false);
+ if (train.route == this) train.route = null;
+ }
+
public static void saveAll(Collection routes, String filename) throws IOException {
BufferedWriter file = new BufferedWriter(new FileWriter(filename));
file.write("{\""+ROUTES+"\":[\n");
@@ -560,7 +564,7 @@ public class Route implements Constants{
if (lastTile instanceof Turnout) addTurnout((Turnout) lastTile,state);
}
- public boolean setSignals(String state) throws IOException {
+ public boolean setSignals(String state) {
for (Signal signal : signals) {
if (!signal.state(state == null ? Signal.GO : state)) return false;
}
diff --git a/src/main/java/de/srsoftware/web4rail/actions/Action.java b/src/main/java/de/srsoftware/web4rail/actions/Action.java
index e147016..668fe47 100644
--- a/src/main/java/de/srsoftware/web4rail/actions/Action.java
+++ b/src/main/java/de/srsoftware/web4rail/actions/Action.java
@@ -45,6 +45,11 @@ public abstract class Action implements Constants {
public Context(Train train) {
this.train = train;
}
+
+ public Context(Route route) {
+ this.route = route;
+ train = route.train;
+ }
}
public Action() {
@@ -54,6 +59,7 @@ public abstract class Action implements Constants {
public static Action create(String type) {
try {
+ if (type.equals("FreeStartBlock")) type = FreePreviousBlocks.class.getSimpleName();
return (Action) Class.forName(PREFIX+"."+type).getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
@@ -86,7 +92,7 @@ public abstract class Action implements Constants {
ConditionalAction.class,
SetSpeed.class,
SetSignalsToStop.class,
- FreeStartBlock.class,
+ FreePreviousBlocks.class,
FinishRoute.class,
TurnTrain.class,
StopAuto.class,
diff --git a/src/main/java/de/srsoftware/web4rail/actions/ActionList.java b/src/main/java/de/srsoftware/web4rail/actions/ActionList.java
index 3e8a7f3..bbf0dfc 100644
--- a/src/main/java/de/srsoftware/web4rail/actions/ActionList.java
+++ b/src/main/java/de/srsoftware/web4rail/actions/ActionList.java
@@ -121,15 +121,16 @@ public class ActionList extends Vector implements Constants{
public boolean fire(Context context) {
LOG.debug("Firing {}",this);
-
+ boolean success = true;
for (Action action : this) {
try {
- action.fire(context);
+ success &= action.fire(context);
} catch (IOException e) {
LOG.warn("Action did not fire properly: {}",action,e);
+ success = false;
}
}
- return true;
+ return success;
}
public int id() {
diff --git a/src/main/java/de/srsoftware/web4rail/actions/FinishRoute.java b/src/main/java/de/srsoftware/web4rail/actions/FinishRoute.java
index d63cd9d..f1bca48 100644
--- a/src/main/java/de/srsoftware/web4rail/actions/FinishRoute.java
+++ b/src/main/java/de/srsoftware/web4rail/actions/FinishRoute.java
@@ -2,11 +2,14 @@ package de.srsoftware.web4rail.actions;
import java.io.IOException;
+import de.srsoftware.web4rail.Route;
+
public class FinishRoute extends Action {
@Override
public boolean fire(Context context) throws IOException {
- context.route.finish();
+ Route route = context.route;
+ if (route != null) route.finish();
return true;
}
}
diff --git a/src/main/java/de/srsoftware/web4rail/actions/FreeStartBlock.java b/src/main/java/de/srsoftware/web4rail/actions/FreePreviousBlocks.java
similarity index 52%
rename from src/main/java/de/srsoftware/web4rail/actions/FreeStartBlock.java
rename to src/main/java/de/srsoftware/web4rail/actions/FreePreviousBlocks.java
index 25748bd..02edb4e 100644
--- a/src/main/java/de/srsoftware/web4rail/actions/FreeStartBlock.java
+++ b/src/main/java/de/srsoftware/web4rail/actions/FreePreviousBlocks.java
@@ -2,11 +2,11 @@ package de.srsoftware.web4rail.actions;
import java.io.IOException;
-public class FreeStartBlock extends Action {
+public class FreePreviousBlocks extends Action {
@Override
public boolean fire(Context context) throws IOException {
- context.route.freeStartBlock();
- return true;
+ if (context.train != null) context.train.resetPreviousBlocks();
+ return false;
}
}
diff --git a/src/main/java/de/srsoftware/web4rail/actions/SetSignalsToStop.java b/src/main/java/de/srsoftware/web4rail/actions/SetSignalsToStop.java
index 819f003..8663552 100644
--- a/src/main/java/de/srsoftware/web4rail/actions/SetSignalsToStop.java
+++ b/src/main/java/de/srsoftware/web4rail/actions/SetSignalsToStop.java
@@ -1,13 +1,11 @@
package de.srsoftware.web4rail.actions;
-import java.io.IOException;
-
import de.srsoftware.web4rail.tiles.Signal;
public class SetSignalsToStop extends Action {
@Override
- public boolean fire(Context context) throws IOException {
+ public boolean fire(Context context) {
context.route.setSignals(Signal.STOP);
return true;
}
diff --git a/src/main/java/de/srsoftware/web4rail/moving/Train.java b/src/main/java/de/srsoftware/web4rail/moving/Train.java
index 1559bab..e03455d 100644
--- a/src/main/java/de/srsoftware/web4rail/moving/Train.java
+++ b/src/main/java/de/srsoftware/web4rail/moving/Train.java
@@ -36,7 +36,6 @@ import de.srsoftware.web4rail.tags.Input;
import de.srsoftware.web4rail.tags.Label;
import de.srsoftware.web4rail.tags.Select;
import de.srsoftware.web4rail.tiles.Block;
-import de.srsoftware.web4rail.tiles.Signal;
public class Train implements Comparable,Constants {
private static final Logger LOG = LoggerFactory.getLogger(Train.class);
@@ -70,6 +69,7 @@ public class Train implements Comparable,Constants {
private Block block = null;
+ private Vector previousBlocks = new Vector();
private class Autopilot extends Thread{
boolean stop = false;
@@ -149,6 +149,47 @@ public class Train implements Comparable,Constants {
return t("Unknown action: {}",params.get(ACTION));
}
+ private Route chooseRoute(Context context) { HashSet routes = block.routes();
+ Vector availableRoutes = new Vector();
+ for (Route rt : routes) {
+ if (rt == route) continue; // andere Route als zuvor wählen
+ if (rt.path().firstElement() != block) continue; // keine Route wählen, die nicht vom aktuellen Block des Zuges startet
+ if (direction != null && rt.startDirection != direction) { // Route ist entgegen der Startrichtung des Zuges
+ if (!pushPull || !block.turnAllowed) { // Zug ist kein Wendezug oder Block erlaubt kein Wenden
+ continue;
+ }
+ }
+ if (!rt.free()) { // keine belegten Routen wählen
+ LOG.debug("{} is not free!",rt);
+ continue;
+ }
+ if (!rt.allowed(context)) continue;
+ availableRoutes.add(rt);
+ }
+ Random rand = new Random();
+ if (availableRoutes.isEmpty()) return null;
+ return availableRoutes.get(rand.nextInt(availableRoutes.size()));
+ }
+
+ @Override
+ public int compareTo(Train o) {
+ return name().compareTo(o.toString());
+ }
+
+ public String directedName() {
+ String result = name();
+ if (direction == null) return result;
+ switch (direction) {
+ case NORTH:
+ case WEST:
+ return '←'+result;
+ case SOUTH:
+ case EAST:
+ return result+'→';
+ }
+ return result;
+ }
+
private Object dropCar(HashMap params) {
String carId = params.get(CAR_ID);
if (carId != null) cars.remove(Car.get(carId));
@@ -188,10 +229,18 @@ public class Train implements Comparable,Constants {
return block;
}
- public void block(Block block) throws IOException {
+ public Train block(Block block, boolean resetPreviousBlocks) {
+ if (this.block == block) return this; // nothing to update
+ if (this.block != null) {
+ this.block.trailingTrain(this);
+ previousBlocks.add(this.block);
+ }
this.block = block;
+ block.train(this);
+ if (resetPreviousBlocks) resetPreviousBlocks();
+ return this;
}
-
+
private Tag carList() {
Tag locoProp = new Tag("li").content(t("Cars:"));
Tag locoList = new Tag("ul").clazz("carlist");
@@ -235,6 +284,7 @@ public class Train implements Comparable,Constants {
public Train heading(Direction dir) {
direction = dir;
+ if (block != null) plan.place(block);
return this;
}
@@ -353,17 +403,7 @@ public class Train implements Comparable,Constants {
}
public String name() {
- String result = (name != null ? name : locos.firstElement().name());
- if (direction == null) return result;
- switch (direction) {
- case NORTH:
- case WEST:
- return '←'+result;
- case SOUTH:
- case EAST:
- return result+'→';
- }
- return result;
+ return (name != null ? name : locos.firstElement().name());
}
private Train name(String newName) {
@@ -438,7 +478,20 @@ public class Train implements Comparable,Constants {
return t("{} stopping at next block.",this);
} else return t("autopilot not active.");
}
+
+ public void removeFromBlock(Block block) {
+ if (block.train() == this) block.train(null);
+ if (this.block == block) this.block = null;
+ previousBlocks.remove(block);
+ }
+ public void resetPreviousBlocks() {
+ for (Block block : previousBlocks) {
+ if (block.train() == this || block.trailingTrain() == this) block.unlock();
+ }
+ previousBlocks.clear();
+ }
+
public static void saveAll(String filename) throws IOException {
BufferedWriter file = new BufferedWriter(new FileWriter(filename));
for (Entry entry:trains.entrySet()) {
@@ -468,44 +521,25 @@ public class Train implements Comparable,Constants {
public String start() throws IOException {
if (block == null) return t("{} not in a block",this);
- if (route != null) route.unlock().setSignals(Signal.STOP);
- HashSet routes = block.routes();
- Vector availableRoutes = new Vector();
+ if (route != null) route.reset(); // reset route previously chosen
Context context = new Context(this);
- for (Route rt : routes) {
- if (rt == route) continue; // andere Route als zuvor wählen
- if (rt.path().firstElement() != block) continue; // keine Route wählen, die nicht vom aktuellen Block des Zuges startet
- if (direction != null && rt.startDirection != direction) { // Route ist entgegen der Startrichtung des Zuges
- if (!pushPull || !block.turnAllowed) { // Zug ist kein Wendezug oder Block erlaubt kein Wenden
- continue;
- }
- }
- if (!rt.free()) { // keine belegten Routen wählen
- LOG.debug("{} is not free!",rt);
- continue;
- }
- if (!rt.allowed(context)) continue;
- availableRoutes.add(rt);
- }
- Random rand = new Random();
- if (availableRoutes.isEmpty()) return t("No free routes from {}",block);
- route = availableRoutes.get(rand.nextInt(availableRoutes.size()));
+ route = chooseRoute(context);
+ if (route == null) return t("No free routes from {}",block);
if (!route.lock()) return t("Was not able to lock {}",route);
- String error = null;
if (direction != route.startDirection) turn();
+
+ String error = null;
if (!route.setTurnouts()) error = t("Was not able to set all turnouts!");
- route.fireSetupActions(context);
+ if (error == null && !route.fireSetupActions(context)) error = t("Was not able to fire all setup actions of route!");
if (error == null && !route.setSignals(null)) error = t("Was not able to set all signals!");
if (error == null && !route.train(this)) error = t("Was not able to assign {} to {}!",this,route);
- if (error == null) {
- setSpeed(128);
- return t("Started {}",this);
+ if (error != null) {
+ route.reset();
+ return error;
}
- route.unlock();
- this.block.train(this); // re-set train on previous block
- this.route = null;
- return error;
+ setSpeed(128);
+ return t("Started {}",this);
}
private Object stopNow() {
@@ -537,9 +571,7 @@ public class Train implements Comparable,Constants {
direction = direction.inverse();
for (Locomotive loco : locos) loco.turn();
}
- if (block != null) try {
- plan.place(block.train(this));
- } catch (IOException e) {}
+ if (block != null) plan.place(block.train(this));
return t("{} turned.",this);
}
@@ -559,9 +591,4 @@ public class Train implements Comparable,Constants {
return this;
}
-
- @Override
- public int compareTo(Train o) {
- return name().compareTo(o.toString());
- }
}
diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Block.java b/src/main/java/de/srsoftware/web4rail/tiles/Block.java
index eaa8551..8734cd3 100644
--- a/src/main/java/de/srsoftware/web4rail/tiles/Block.java
+++ b/src/main/java/de/srsoftware/web4rail/tiles/Block.java
@@ -22,6 +22,7 @@ public abstract class Block extends StretchableTile{
private static final String ALLOW_TURN = "allowTurn";
public boolean turnAllowed = false;
+ private Train trailingTrain = null;
private static final String TRAIN = Train.class.getSimpleName();
@@ -34,9 +35,9 @@ public abstract class Block extends StretchableTile{
@Override
public boolean free() {
- return train == null && super.free();
+ return super.free() && trailingTrain == null;
}
-
+
@Override
public JSONObject json() {
JSONObject json = super.json();
@@ -53,7 +54,7 @@ public abstract class Block extends StretchableTile{
turnAllowed = json.has(ALLOW_TURN) && json.getBoolean(ALLOW_TURN);
if (json.has(TRAIN)) {
Train tr = Train.get(json.getInt(TRAIN));
- train(tr);
+ train(tr.block(this, false));
}
return this;
}
@@ -91,9 +92,11 @@ public abstract class Block extends StretchableTile{
@Override
public Tag tag(Map replacements) throws IOException {
if (replacements == null) replacements = new HashMap();
- replacements.put("%text%",train == null ? name : train.name());
+ replacements.put("%text%",name);
+ if (trailingTrain != null) replacements.put("%text%","("+trailingTrain.name()+")");
+ if (train != null) replacements.put("%text%",train.directedName());
Tag tag = super.tag(replacements);
- if (train != null) tag.clazz(tag.get("class")+" occupied");
+ if (train != null || trailingTrain != null) tag.clazz(tag.get("class")+" occupied");
return tag;
}
@@ -107,11 +110,20 @@ public abstract class Block extends StretchableTile{
return getClass().getSimpleName()+"("+name+") @ ("+x+","+y+")";
}
- public Tile train(Train newTrain) throws IOException {
- if (train == newTrain) return this;
- if (train != null) train.block(null); // vorherigen Zug rauswerfen
- if (newTrain != null) newTrain.block(this);
- return super.train(newTrain);
+ public void trailingTrain(Train train) {
+ trailingTrain = train;
+ this.train = null;
+ plan.place(this);
+ }
+
+ public Train trailingTrain() {
+ return trailingTrain;
+ }
+
+ @Override
+ public void unlock() {
+ trailingTrain = null;
+ super.unlock();
}
@Override
@@ -119,14 +131,14 @@ public abstract class Block extends StretchableTile{
if (params.containsKey(NAME)) name=params.get(NAME);
if (params.containsKey(TRAIN)) {
int trainId = Integer.parseInt(params.get(TRAIN));
- Train t = Train.get(trainId);
- if (t != null) {
- Block oldBlock = t.block();
- if (oldBlock != null) oldBlock.train(null);
- train(t);
- }
+ if (trainId == 0) {
+ train(null);
+ } else {
+ Train t = Train.get(trainId);
+ if (t != null) train = t.block(this,true);
+ }
}
turnAllowed = params.containsKey(ALLOW_TURN) && params.get(ALLOW_TURN).equals("on");
return super.update(params);
- }
+ }
}
diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Relay.java b/src/main/java/de/srsoftware/web4rail/tiles/Relay.java
index d71025f..df5a92a 100644
--- a/src/main/java/de/srsoftware/web4rail/tiles/Relay.java
+++ b/src/main/java/de/srsoftware/web4rail/tiles/Relay.java
@@ -181,10 +181,8 @@ public class Relay extends Tile implements Device{
@Override
public void onSuccess() {
super.onSuccess();
- try {
- Relay.this.state = newState;
- plan.place(Relay.this);
- } catch (IOException e) {}
+ Relay.this.state = newState;
+ plan.place(Relay.this);
}
@Override
diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Signal.java b/src/main/java/de/srsoftware/web4rail/tiles/Signal.java
index 15b326e..5020f80 100644
--- a/src/main/java/de/srsoftware/web4rail/tiles/Signal.java
+++ b/src/main/java/de/srsoftware/web4rail/tiles/Signal.java
@@ -26,9 +26,13 @@ public abstract class Signal extends Tile{
public abstract boolean isAffectedFrom(Direction dir);
- public boolean state(String state) throws IOException {
+ public boolean state(String state) {
this.state = state;
- plan.stream("place "+tag(null));
+ try {
+ plan.stream("place "+tag(null));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
return true;
}
diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java
index 41cda65..ac5022c 100644
--- a/src/main/java/de/srsoftware/web4rail/tiles/Tile.java
+++ b/src/main/java/de/srsoftware/web4rail/tiles/Tile.java
@@ -95,7 +95,10 @@ public abstract class Tile implements Constants{
}
public boolean free() {
- return (!disabled) && route == null;
+ if (disabled) return false;
+ if (route != null) return false;
+ if (train != null) return false;
+ return true;
}
public int height() {
@@ -160,8 +163,9 @@ public abstract class Tile implements Constants{
return this;
}
- public Tile lock(Route lockingRoute) throws IOException {
- if (route != null && route != lockingRoute) throw new IllegalStateException(this.toString());
+ public Tile lock(Route lockingRoute) {
+ if (route == lockingRoute) return this;
+ if (route != null && lockingRoute != null) throw new IllegalStateException(this.toString());
route = lockingRoute;
return plan.place(this);
}
@@ -353,12 +357,13 @@ public abstract class Tile implements Constants{
return train;
}
- public Tile train(Train train) throws IOException {
+ public Tile train(Train train) {
+ if (this.train == train) return this; // nothing to update
this.train = train;
return plan.place(this);
}
- public void unlock() throws IOException {
+ public void unlock() {
route = null;
train = null;
plan.place(this);
diff --git a/src/main/java/de/srsoftware/web4rail/tiles/Turnout.java b/src/main/java/de/srsoftware/web4rail/tiles/Turnout.java
index fc7e979..a4b33e3 100644
--- a/src/main/java/de/srsoftware/web4rail/tiles/Turnout.java
+++ b/src/main/java/de/srsoftware/web4rail/tiles/Turnout.java
@@ -149,10 +149,8 @@ public abstract class Turnout extends Tile implements Device{
@Override
public void onSuccess() {
super.onSuccess();
- try {
- Turnout.this.state = newState;
- plan.place(Turnout.this);
- } catch (IOException e) {}
+ Turnout.this.state = newState;
+ plan.place(Turnout.this);
}
@Override