added javadoc comments to some classes
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>de.srsoftware</groupId>
|
<groupId>de.srsoftware</groupId>
|
||||||
<artifactId>web4rail</artifactId>
|
<artifactId>web4rail</artifactId>
|
||||||
<version>0.7.12</version>
|
<version>0.7.13</version>
|
||||||
<name>Web4Rail</name>
|
<name>Web4Rail</name>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<description>Java Model Railway Control</description>
|
<description>Java Model Railway Control</description>
|
||||||
|
|||||||
@@ -32,10 +32,29 @@ import de.srsoftware.web4rail.moving.Car;
|
|||||||
import de.srsoftware.web4rail.moving.Locomotive;
|
import de.srsoftware.web4rail.moving.Locomotive;
|
||||||
import de.srsoftware.web4rail.moving.Train;
|
import de.srsoftware.web4rail.moving.Train;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point class for the Web4Rail application
|
||||||
|
*
|
||||||
|
* @author Stephan Richter, SRSoftware
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class Application implements Constants{
|
public class Application implements Constants{
|
||||||
private static Plan plan;
|
private static Plan plan; // the track layout in use
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Application.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Application.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* entry point for the application:<br/>
|
||||||
|
* creates a http server, loads a plan and directs a browser to the respective page
|
||||||
|
* @param args
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws InstantiationException
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* @throws InvocationTargetException
|
||||||
|
* @throws NoSuchMethodException
|
||||||
|
* @throws SecurityException
|
||||||
|
*/
|
||||||
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
||||||
Configuration config = new Configuration(Configuration.dir("Web4Rail")+"/app.config");
|
Configuration config = new Configuration(Configuration.dir("Web4Rail")+"/app.config");
|
||||||
LOG.debug("config: {}",config);
|
LOG.debug("config: {}",config);
|
||||||
@@ -55,6 +74,10 @@ public class Application implements Constants{
|
|||||||
Desktop.getDesktop().browse(URI.create("http://"+InetAddress.getLocalHost().getHostName()+":"+config.getInt(PORT)+"/plan"));
|
Desktop.getDesktop().browse(URI.create("http://"+InetAddress.getLocalHost().getHostName()+":"+config.getInt(PORT)+"/plan"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper class creating unique ids for use throuout the application
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public static int createId() {
|
public static int createId() {
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1);
|
Thread.sleep(1);
|
||||||
@@ -64,6 +87,19 @@ public class Application implements Constants{
|
|||||||
return new Date().hashCode();
|
return new Date().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handles request from clients by delegating them to respective classes
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws InstantiationException
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* @throws InvocationTargetException
|
||||||
|
* @throws NoSuchMethodException
|
||||||
|
* @throws SecurityException
|
||||||
|
*/
|
||||||
private static Object handle(HashMap<String, String> params) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
private static Object handle(HashMap<String, String> params) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
||||||
|
|
||||||
String realm = params.get(REALM);
|
String realm = params.get(REALM);
|
||||||
@@ -94,6 +130,11 @@ public class Application implements Constants{
|
|||||||
return t("Unknown realm: {}",params.get(REALM));
|
return t("Unknown realm: {}",params.get(REALM));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a map from url-encoded data
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private static HashMap<String, String> inflate(String data) {
|
private static HashMap<String, String> inflate(String data) {
|
||||||
//LOG.debug("inflate({})",data);
|
//LOG.debug("inflate({})",data);
|
||||||
HashMap<String, String> params = new HashMap<String, String>();
|
HashMap<String, String> params = new HashMap<String, String>();
|
||||||
@@ -108,10 +149,21 @@ public class Application implements Constants{
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a map from url-encoded data
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private static HashMap<String, String> inflate(byte[] data) {
|
private static HashMap<String, String> inflate(byte[] data) {
|
||||||
return inflate(new String(data,UTF8));
|
return inflate(new String(data,UTF8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a response generated from the application to a given client
|
||||||
|
* @param client
|
||||||
|
* @param response
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private static void send(HttpExchange client, Object response) throws IOException {
|
private static void send(HttpExchange client, Object response) throws IOException {
|
||||||
byte[] html;
|
byte[] html;
|
||||||
if (response instanceof Page) {
|
if (response instanceof Page) {
|
||||||
@@ -145,6 +197,13 @@ public class Application implements Constants{
|
|||||||
os.close();
|
os.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends an error to a given client
|
||||||
|
* @param client
|
||||||
|
* @param code
|
||||||
|
* @param msg
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private static void sendError(HttpExchange client, int code, String msg) throws IOException {
|
private static void sendError(HttpExchange client, int code, String msg) throws IOException {
|
||||||
client.sendResponseHeaders(code, msg.length());
|
client.sendResponseHeaders(code, msg.length());
|
||||||
LOG.error(msg);
|
LOG.error(msg);
|
||||||
@@ -153,6 +212,11 @@ public class Application implements Constants{
|
|||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a requested file to the given client
|
||||||
|
* @param client
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private static void sendFile(HttpExchange client) throws IOException {
|
private static void sendFile(HttpExchange client) throws IOException {
|
||||||
URI uri = client.getRequestURI();
|
URI uri = client.getRequestURI();
|
||||||
File file = new File(System.getProperty("user.dir")+"/resources"+uri);
|
File file = new File(System.getProperty("user.dir")+"/resources"+uri);
|
||||||
@@ -170,6 +234,11 @@ public class Application implements Constants{
|
|||||||
sendError(client,404,t("Could not find \"{}\"",uri));
|
sendError(client,404,t("Could not find \"{}\"",uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a response to a given client
|
||||||
|
* @param client
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private static void sendPlan(HttpExchange client) throws IOException {
|
private static void sendPlan(HttpExchange client) throws IOException {
|
||||||
try {
|
try {
|
||||||
HashMap<String, String> params = inflate(client.getRequestBody().readAllBytes());
|
HashMap<String, String> params = inflate(client.getRequestBody().readAllBytes());
|
||||||
@@ -189,6 +258,12 @@ public class Application implements Constants{
|
|||||||
send(client,new Page().append(e.getMessage()));
|
send(client,new Page().append(e.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* establishes an event stream connection between the application and a given client
|
||||||
|
* @param client
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private static void stream(HttpExchange client) throws IOException {
|
private static void stream(HttpExchange client) throws IOException {
|
||||||
client.getResponseHeaders().set("content-type", "text/event-stream");
|
client.getResponseHeaders().set("content-type", "text/event-stream");
|
||||||
client.sendResponseHeaders(200, 0);
|
client.sendResponseHeaders(200, 0);
|
||||||
@@ -196,6 +271,12 @@ public class Application implements Constants{
|
|||||||
plan.addClient(sseWriter);
|
plan.addClient(sseWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shorthand for Translations.get(text,fills)
|
||||||
|
* @param text
|
||||||
|
* @param fills
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private static String t(String text, Object...fills) {
|
private static String t(String text, Object...fills) {
|
||||||
return Translation.get(Application.class, text, fills);
|
return Translation.get(Application.class, text, fills);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,18 +7,31 @@ import java.util.concurrent.TimeoutException;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handles SRCP commands and their replies received from the SRCP daemon
|
||||||
|
* @author Stephan Richter, SRSoftware
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class Command {
|
public class Command {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Command.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Command.class);
|
||||||
private String command;
|
private String command;
|
||||||
private Reply reply = null;
|
private Reply reply = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* encapsulates a reply received from the SRCP daemon
|
||||||
|
*
|
||||||
|
*/
|
||||||
public static class Reply{
|
public static class Reply{
|
||||||
private long secs;
|
private long secs;
|
||||||
private int milis;
|
private int milis;
|
||||||
private int code;
|
private int code;
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parses a reply from the SRCP daemon
|
||||||
|
* @param scanner
|
||||||
|
*/
|
||||||
public Reply(Scanner scanner) {
|
public Reply(Scanner scanner) {
|
||||||
String word = scanner.next();
|
String word = scanner.next();
|
||||||
secs = Long.parseLong(word.substring(0, word.length()-4));
|
secs = Long.parseLong(word.substring(0, word.length()-4));
|
||||||
@@ -28,6 +41,11 @@ public class Command {
|
|||||||
LOG.info("recv {}.{} {} {}.",secs,milis,code,message);
|
LOG.info("recv {}.{} {} {}.",secs,milis,code,message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a reply with given data
|
||||||
|
* @param code
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
public Reply(int code, String message) {
|
public Reply(int code, String message) {
|
||||||
secs = new Date().getTime();
|
secs = new Date().getTime();
|
||||||
milis = (int) (secs % 1000);
|
milis = (int) (secs % 1000);
|
||||||
@@ -36,14 +54,25 @@ public class Command {
|
|||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checks if a response has a specific code
|
||||||
|
* @param code
|
||||||
|
* @return true if the given code equals the response's code
|
||||||
|
*/
|
||||||
public boolean is(int code) {
|
public boolean is(int code) {
|
||||||
return code == this.code;
|
return code == this.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true, if the response code is between 200 and 300
|
||||||
|
*/
|
||||||
public boolean succeeded() {
|
public boolean succeeded() {
|
||||||
return (code > 199 && code < 300);
|
return (code > 199 && code < 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the message passed along with the response from the SRCP deameon
|
||||||
|
*/
|
||||||
public String message() {
|
public String message() {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
@@ -54,15 +83,27 @@ public class Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* encapsulates a command to be send to the SRCP daemon
|
||||||
|
* @param command
|
||||||
|
*/
|
||||||
public Command(String command) {
|
public Command(String command) {
|
||||||
this.command = command;
|
this.command = command;
|
||||||
LOG.debug("Created new Command({}).",command);
|
LOG.debug("Created new Command({}).",command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called, if the response indicates an error
|
||||||
|
* @param reply
|
||||||
|
*/
|
||||||
protected void onFailure(Reply reply) {
|
protected void onFailure(Reply reply) {
|
||||||
LOG.warn("onFailure({})",command);
|
LOG.warn("onFailure({})",command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called, when a response from the SRCP daemon is received
|
||||||
|
* @param reply
|
||||||
|
*/
|
||||||
public void onResponse(Reply reply) {
|
public void onResponse(Reply reply) {
|
||||||
this.reply = reply;
|
this.reply = reply;
|
||||||
if (reply.succeeded()) {
|
if (reply.succeeded()) {
|
||||||
@@ -70,18 +111,36 @@ public class Command {
|
|||||||
} else onFailure(reply);
|
} else onFailure(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called, when the response from the SRCP daemon indicates success of the operation
|
||||||
|
*/
|
||||||
public void onSuccess(){
|
public void onSuccess(){
|
||||||
LOG.debug("onSuccess({})",command);
|
LOG.debug("onSuccess({})",command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parses the reply from the SRCP daemon
|
||||||
|
* @param scanner
|
||||||
|
*/
|
||||||
public void readReplyFrom(Scanner scanner) {
|
public void readReplyFrom(Scanner scanner) {
|
||||||
onResponse(new Reply(scanner));
|
onResponse(new Reply(scanner));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* waits for the reply from the SRCP daemon for one second
|
||||||
|
* @return
|
||||||
|
* @throws TimeoutException
|
||||||
|
*/
|
||||||
public Reply reply() throws TimeoutException {
|
public Reply reply() throws TimeoutException {
|
||||||
return reply(100);
|
return reply(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* waits for the reply from the SRCP daemon for a given timeout
|
||||||
|
* @param timeout time (in 10ms units) to wait, before a timeout is thrown
|
||||||
|
* @return
|
||||||
|
* @throws TimeoutException
|
||||||
|
*/
|
||||||
public Reply reply(int timeout) throws TimeoutException {
|
public Reply reply(int timeout) throws TimeoutException {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
while (reply == null) try {
|
while (reply == null) try {
|
||||||
@@ -93,6 +152,10 @@ public class Command {
|
|||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate a timeout exception
|
||||||
|
* @throws TimeoutException
|
||||||
|
*/
|
||||||
private void timeout() throws TimeoutException {
|
private void timeout() throws TimeoutException {
|
||||||
String msg = command;
|
String msg = command;
|
||||||
command = null;
|
command = null;
|
||||||
|
|||||||
@@ -3,6 +3,14 @@ package de.srsoftware.web4rail;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import de.keawe.tools.translations.Translation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this interface collects constants inherited to other classes of this application
|
||||||
|
*
|
||||||
|
* @author Stephan Richter, SRSoftware
|
||||||
|
*
|
||||||
|
*/
|
||||||
public interface Constants {
|
public interface Constants {
|
||||||
public static final String ACTION = "action";
|
public static final String ACTION = "action";
|
||||||
public static final String ACTION_ADD = "add";
|
public static final String ACTION_ADD = "add";
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ import de.srsoftware.web4rail.tags.Form;
|
|||||||
import de.srsoftware.web4rail.tags.Input;
|
import de.srsoftware.web4rail.tags.Input;
|
||||||
import de.srsoftware.web4rail.tags.Label;
|
import de.srsoftware.web4rail.tags.Label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* abstraction of a SRCP daemon (control unit)
|
||||||
|
*
|
||||||
|
* @author Stephan Richter, SRSoftware
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class ControlUnit extends Thread implements Constants{
|
public class ControlUnit extends Thread implements Constants{
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ControlUnit.class);
|
private static final Logger LOG = LoggerFactory.getLogger(ControlUnit.class);
|
||||||
private static final String DEFAULT_HOST = "localhost";
|
private static final String DEFAULT_HOST = "localhost";
|
||||||
@@ -53,6 +59,11 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* performs a handshake as specified in the SRCP protocol
|
||||||
|
* @throws TimeoutException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private void handshake() throws TimeoutException, IOException {
|
private void handshake() throws TimeoutException, IOException {
|
||||||
String proto = null;
|
String proto = null;
|
||||||
if (scanner.hasNext()) {
|
if (scanner.hasNext()) {
|
||||||
@@ -79,6 +90,9 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
if (!command.reply().succeeded()) throw new IOException("Handshake failed: "+command.reply());
|
if (!command.reply().succeeded()) throw new IOException("Handshake failed: "+command.reply());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return json string containing the connection information
|
||||||
|
*/
|
||||||
private JSONObject json() {
|
private JSONObject json() {
|
||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
json.put(HOST, host);
|
json.put(HOST, host);
|
||||||
@@ -87,6 +101,11 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* load connection information from file
|
||||||
|
* @param filename
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void load(String filename) throws IOException {
|
public void load(String filename) throws IOException {
|
||||||
BufferedReader file = new BufferedReader(new FileReader(filename));
|
BufferedReader file = new BufferedReader(new FileReader(filename));
|
||||||
JSONObject json = new JSONObject(file.readLine());
|
JSONObject json = new JSONObject(file.readLine());
|
||||||
@@ -96,6 +115,11 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
if (json.has(HOST)) host = json.getString(HOST);
|
if (json.has(HOST)) host = json.getString(HOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test method
|
||||||
|
* @param args
|
||||||
|
* @throws InterruptedException
|
||||||
|
*/
|
||||||
public static void main(String[] args) throws InterruptedException {
|
public static void main(String[] args) throws InterruptedException {
|
||||||
ControlUnit cu = new ControlUnit(null).setEndpoint("Modellbahn", DEFAULT_PORT).setBus(1).restart();
|
ControlUnit cu = new ControlUnit(null).setEndpoint("Modellbahn", DEFAULT_PORT).setBus(1).restart();
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
@@ -116,6 +140,11 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
cu.end();
|
cu.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* process actions related to the SRCP daemon
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Object process(HashMap<String, String> params) {
|
public Object process(HashMap<String, String> params) {
|
||||||
switch (params.get(ACTION)) {
|
switch (params.get(ACTION)) {
|
||||||
case ACTION_CONNECT:
|
case ACTION_CONNECT:
|
||||||
@@ -134,11 +163,19 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
return t("Unknown action: {}",params.get(ACTION));
|
return t("Unknown action: {}",params.get(ACTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* turn of power immediately
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Object emergency() {
|
public Object emergency() {
|
||||||
power = true;
|
power = true;
|
||||||
return togglePower();
|
return togglePower();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate a properties view for the client
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Object properties() {
|
public Object properties() {
|
||||||
Window win = new Window("cu-props", t("Properties of the control unit"));
|
Window win = new Window("cu-props", t("Properties of the control unit"));
|
||||||
Form form = new Form();
|
Form form = new Form();
|
||||||
@@ -155,6 +192,11 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
return win;
|
return win;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add a command to the queue of commands to be sent to the server
|
||||||
|
* @param command
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Command queue(Command command) {
|
public Command queue(Command command) {
|
||||||
queue.add(command);
|
queue.add(command);
|
||||||
return command;
|
return command;
|
||||||
@@ -170,6 +212,9 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* thread, that repeatedly checks the queue for new commands and sends them to the SRCP daemon
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
while (!stopped) {
|
while (!stopped) {
|
||||||
@@ -191,6 +236,11 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* save settings to file
|
||||||
|
* @param filename
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void save(String filename) throws IOException {
|
public void save(String filename) throws IOException {
|
||||||
BufferedWriter file = new BufferedWriter(new FileWriter(filename));
|
BufferedWriter file = new BufferedWriter(new FileWriter(filename));
|
||||||
file.write(json()+"\n");
|
file.write(json()+"\n");
|
||||||
@@ -211,11 +261,22 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
command.readReplyFrom(scanner);
|
command.readReplyFrom(scanner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* defines the bus on the SRCP deamon, to which commands shall be assigned
|
||||||
|
* @param bus
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private ControlUnit setBus(int bus) {
|
private ControlUnit setBus(int bus) {
|
||||||
this.bus = bus;
|
this.bus = bus;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set up the connection endpoint
|
||||||
|
* @param newHost
|
||||||
|
* @param newPort
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public ControlUnit setEndpoint(String newHost, int newPort){
|
public ControlUnit setEndpoint(String newHost, int newPort){
|
||||||
host = newHost;
|
host = newHost;
|
||||||
port = newPort;
|
port = newPort;
|
||||||
@@ -235,10 +296,20 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
super.start();
|
super.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shorthand for Translation.get(text,fills)
|
||||||
|
* @param text
|
||||||
|
* @param fills
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private static String t(String text,Object...fills) {
|
private static String t(String text,Object...fills) {
|
||||||
return Translation.get(Application.class, text, fills);
|
return Translation.get(Application.class, text, fills);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* togge power on/off at the SRCP daemon
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private Command togglePower() {
|
private Command togglePower() {
|
||||||
power = !power;
|
power = !power;
|
||||||
String PW = power?"ON":"OFF";
|
String PW = power?"ON":"OFF";
|
||||||
@@ -259,6 +330,11 @@ public class ControlUnit extends Thread implements Constants{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update connection parameters
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public String update(HashMap<String, String> params) {
|
public String update(HashMap<String, String> params) {
|
||||||
if (params.containsKey(HOST)) host = params.get(HOST);
|
if (params.containsKey(HOST)) host = params.get(HOST);
|
||||||
if (params.containsKey(PORT)) port = Integer.parseInt(params.get(PORT));
|
if (params.containsKey(PORT)) port = Integer.parseInt(params.get(PORT));
|
||||||
|
|||||||
@@ -4,8 +4,12 @@ import java.util.Vector;
|
|||||||
|
|
||||||
import de.srsoftware.tools.Tag;
|
import de.srsoftware.tools.Tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* helper class to create html pages
|
||||||
|
* @author Stephan Richter, SRSoftware
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class Page {
|
public class Page {
|
||||||
private StringBuffer buf;
|
private StringBuffer buf;
|
||||||
private Vector<String> cssFiles = new Vector<String>();
|
private Vector<String> cssFiles = new Vector<String>();
|
||||||
@@ -15,11 +19,19 @@ public class Page {
|
|||||||
buf = new StringBuffer();
|
buf = new StringBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Page append(Object code) {
|
||||||
public String toString() {
|
buf.append(code);
|
||||||
return head().append(body(buf)).toString();
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StringBuffer body(StringBuffer content) {
|
||||||
|
return new StringBuffer()
|
||||||
|
.append("\t<body>\n")
|
||||||
|
.append(content)
|
||||||
|
.append("\t</body>\n")
|
||||||
|
.append("</html>\n");
|
||||||
|
}
|
||||||
|
|
||||||
private StringBuffer head() {
|
private StringBuffer head() {
|
||||||
StringBuffer sb = new StringBuffer()
|
StringBuffer sb = new StringBuffer()
|
||||||
.append("<html>\n")
|
.append("<html>\n")
|
||||||
@@ -33,31 +45,23 @@ public class Page {
|
|||||||
}
|
}
|
||||||
return sb.append("\t</head>\n");
|
return sb.append("\t</head>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringBuffer body(StringBuffer content) {
|
|
||||||
return new StringBuffer()
|
|
||||||
.append("\t<body>\n")
|
|
||||||
.append(content)
|
|
||||||
.append("\t</body>\n")
|
|
||||||
.append("</html>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringBuffer html() {
|
public StringBuffer html() {
|
||||||
return head().append(body(buf));
|
return head().append(body(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Page append(Object code) {
|
|
||||||
buf.append(code);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Page style(String cssPath) {
|
|
||||||
cssFiles.add(cssPath);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Page js(String jsPath) {
|
public Page js(String jsPath) {
|
||||||
jsFiles.add(jsPath);
|
jsFiles.add(jsPath);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Page style(String cssPath) {
|
||||||
|
cssFiles.add(cssPath);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return head().append(body(buf)).toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,21 @@ import de.srsoftware.web4rail.tiles.TurnoutRN;
|
|||||||
import de.srsoftware.web4rail.tiles.TurnoutRS;
|
import de.srsoftware.web4rail.tiles.TurnoutRS;
|
||||||
import de.srsoftware.web4rail.tiles.TurnoutRW;
|
import de.srsoftware.web4rail.tiles.TurnoutRW;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is a central part of the Application, as it loads, holds and saves all kinds of information:
|
||||||
|
* <ul>
|
||||||
|
* <li>Tack layout</li>
|
||||||
|
* <li>Trains and Cars</li>
|
||||||
|
* <li>Routes</li>
|
||||||
|
* <li>...</li>
|
||||||
|
* </ul>
|
||||||
|
* @author Stephan Richter, SRSoftware
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class Plan implements Constants{
|
public class Plan implements Constants{
|
||||||
|
/**
|
||||||
|
* The four directions Trains can be within blocks
|
||||||
|
*/
|
||||||
public enum Direction{
|
public enum Direction{
|
||||||
NORTH, SOUTH, EAST, WEST;
|
NORTH, SOUTH, EAST, WEST;
|
||||||
|
|
||||||
@@ -73,6 +87,9 @@ public class Plan implements Constants{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This thread sends a heartbea to the client
|
||||||
|
*/
|
||||||
private class Heartbeat extends Thread {
|
private class Heartbeat extends Thread {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -96,15 +113,31 @@ public class Plan implements Constants{
|
|||||||
private static final HashMap<OutputStreamWriter,Integer> clients = new HashMap<OutputStreamWriter, Integer>();
|
private static final HashMap<OutputStreamWriter,Integer> clients = new HashMap<OutputStreamWriter, Integer>();
|
||||||
private static final String ACTION_QR = "qrcode";
|
private static final String ACTION_QR = "qrcode";
|
||||||
|
|
||||||
public HashMap<String,Tile> tiles = new HashMap<String,Tile>();
|
public HashMap<String,Tile> tiles = new HashMap<String,Tile>(); // The list of tiles of this plan, i.e. the Track layout
|
||||||
private HashSet<Block> blocks = new HashSet<Block>();
|
private HashSet<Block> blocks = new HashSet<Block>(); // the list of tiles, that are blocks
|
||||||
private HashMap<Integer, Route> routes = new HashMap<Integer, Route>();
|
private HashMap<Integer, Route> routes = new HashMap<Integer, Route>(); // the list of routes of the track layout
|
||||||
private ControlUnit controlUnit = new ControlUnit(this);
|
private ControlUnit controlUnit = new ControlUnit(this); // the control unit, to which the plan is connected
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new plan, starts to send heart beats
|
||||||
|
*/
|
||||||
public Plan() {
|
public Plan() {
|
||||||
new Heartbeat().start();
|
new Heartbeat().start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manages plan-related commands
|
||||||
|
* @param params the parameters passed from the client
|
||||||
|
* @return Object returned to the client
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws InstantiationException
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* @throws InvocationTargetException
|
||||||
|
* @throws NoSuchMethodException
|
||||||
|
* @throws SecurityException
|
||||||
|
*/
|
||||||
public Object action(HashMap<String, String> params) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
public Object action(HashMap<String, String> params) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
||||||
switch (params.get(ACTION)) {
|
switch (params.get(ACTION)) {
|
||||||
case ACTION_ADD:
|
case ACTION_ADD:
|
||||||
@@ -123,6 +156,11 @@ public class Plan implements Constants{
|
|||||||
return t("Unknown action: {}",params.get(ACTION));
|
return t("Unknown action: {}",params.get(ACTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generates the action menu that is appended to the plan
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private Tag actionMenu() throws IOException {
|
private Tag actionMenu() throws IOException {
|
||||||
Tag actionMenu = new Tag("div").clazz("actions").content(t("Actions"));
|
Tag actionMenu = new Tag("div").clazz("actions").content(t("Actions"));
|
||||||
Tag actions = new Tag("div").clazz("list").content("");
|
Tag actions = new Tag("div").clazz("list").content("");
|
||||||
@@ -133,17 +171,45 @@ public class Plan implements Constants{
|
|||||||
return actions.addTo(actionMenu);
|
return actions.addTo(actionMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attaches a new client to the event stream of the plan
|
||||||
|
* @param client
|
||||||
|
*/
|
||||||
public void addClient(OutputStreamWriter client) {
|
public void addClient(OutputStreamWriter client) {
|
||||||
LOG.debug("Client connected.");
|
LOG.debug("Client connected.");
|
||||||
clients.put(client, 0);
|
clients.put(client, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper function: creates a list element with a link that will call the <it>clickTile</it> function of the client side javascript.
|
||||||
|
* @param tile the tile a click on which shall be simulated
|
||||||
|
* @param content the text to be displayed to the user
|
||||||
|
* @param list the tag to which the link tag shall be added
|
||||||
|
* @return returns the list element itself
|
||||||
|
* TODO: replace occurences by calls to <it>return request({...});</li>, then remove clickTile from the client javascript
|
||||||
|
*/
|
||||||
public static Tag addLink(Tile tile,String content,Tag list) {
|
public static Tag addLink(Tile tile,String content,Tag list) {
|
||||||
Tag li = new Tag("li");
|
Tag li = new Tag("li");
|
||||||
new Tag("span").clazz("link").attr("onclick", "return clickTile("+tile.x+","+tile.y+");").content(content).addTo(li).addTo(list);
|
new Tag("span").clazz("link").attr("onclick", "return clickTile("+tile.x+","+tile.y+");").content(content).addTo(li).addTo(list);
|
||||||
return li;
|
return li;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add a tile of the specified class to the track layout
|
||||||
|
* @param clazz
|
||||||
|
* @param xs
|
||||||
|
* @param ys
|
||||||
|
* @param configJson
|
||||||
|
* @return
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws InstantiationException
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* @throws InvocationTargetException
|
||||||
|
* @throws NoSuchMethodException
|
||||||
|
* @throws SecurityException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private String addTile(String clazz, String xs, String ys, String configJson) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException {
|
private String addTile(String clazz, String xs, String ys, String configJson) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, IOException {
|
||||||
int x = Integer.parseInt(xs);
|
int x = Integer.parseInt(xs);
|
||||||
int y = Integer.parseInt(ys);
|
int y = Integer.parseInt(ys);
|
||||||
@@ -161,6 +227,10 @@ public class Plan implements Constants{
|
|||||||
return t("Added {}",tile.getClass().getSimpleName());
|
return t("Added {}",tile.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* search all possible routes in the plan
|
||||||
|
* @return a string giving information how many routes have been found
|
||||||
|
*/
|
||||||
private String analyze() {
|
private String analyze() {
|
||||||
Vector<Route> routes = new Vector<Route>();
|
Vector<Route> routes = new Vector<Route>();
|
||||||
for (Block block : blocks) {
|
for (Block block : blocks) {
|
||||||
@@ -175,19 +245,38 @@ public class Plan implements Constants{
|
|||||||
return t("Found {} routes.",routes.size());
|
return t("Found {} routes.",routes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the list of blocks known to the plan
|
||||||
|
*/
|
||||||
public Collection<Block> blocks() {
|
public Collection<Block> blocks() {
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calls tile.click()
|
||||||
|
* @param tile
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private Object click(Tile tile) throws IOException {
|
private Object click(Tile tile) throws IOException {
|
||||||
if (tile == null) return null;
|
if (tile == null) return null;
|
||||||
return tile.click();
|
return tile.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the control unit currently connected to the plan
|
||||||
|
*/
|
||||||
public ControlUnit controlUnit() {
|
public ControlUnit controlUnit() {
|
||||||
return controlUnit;
|
return controlUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* completes a given route during a call to {@link #analyze()}.
|
||||||
|
* It therefore traces where the current part of the route comes from and where it may go.
|
||||||
|
* @param route an incomplete route, that shall be completed
|
||||||
|
* @param connector
|
||||||
|
* @return the set of routes, that result from the tracing operation
|
||||||
|
*/
|
||||||
private Collection<Route> follow(Route route, Connector connector) {
|
private Collection<Route> follow(Route route, Connector connector) {
|
||||||
Tile tile = get(Tile.id(connector.x,connector.y),false);
|
Tile tile = get(Tile.id(connector.x,connector.y),false);
|
||||||
Vector<Route> results = new Vector<>();
|
Vector<Route> results = new Vector<>();
|
||||||
@@ -209,7 +298,6 @@ public class Plan implements Constants{
|
|||||||
}
|
}
|
||||||
Map<Connector, State> connectors = tile.connections(connector.from);
|
Map<Connector, State> connectors = tile.connections(connector.from);
|
||||||
List<Route>routes = route.multiply(connectors.size());
|
List<Route>routes = route.multiply(connectors.size());
|
||||||
LOG.debug("{}",tile);
|
|
||||||
if (connectors.size()>1) LOG.debug("SPLITTING @ {}",tile);
|
if (connectors.size()>1) LOG.debug("SPLITTING @ {}",tile);
|
||||||
|
|
||||||
for (Entry<Connector, State> entry: connectors.entrySet()) {
|
for (Entry<Connector, State> entry: connectors.entrySet()) {
|
||||||
@@ -223,6 +311,12 @@ public class Plan implements Constants{
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the tile referenced by the tile id
|
||||||
|
* @param tileId a combination of the coordinates of the requested tile
|
||||||
|
* @param resolveShadows if this is set to true, this function will return the overlaying tiles, if the id belongs to a shadow tile.
|
||||||
|
* @return the tile belonging to the id, or the overlaying tile if the respective tile is a shadow tile.
|
||||||
|
*/
|
||||||
public Tile get(String tileId,boolean resolveShadows) {
|
public Tile get(String tileId,boolean resolveShadows) {
|
||||||
Tile tile = tiles.get(tileId);
|
Tile tile = tiles.get(tileId);
|
||||||
if (resolveShadows && tile instanceof Shadow) tile = ((Shadow)tile).overlay();
|
if (resolveShadows && tile instanceof Shadow) tile = ((Shadow)tile).overlay();
|
||||||
@@ -230,6 +324,11 @@ public class Plan implements Constants{
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generates the hardware menu attached to the plan
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private Tag hardwareMenu() throws IOException {
|
private Tag hardwareMenu() throws IOException {
|
||||||
Tag tileMenu = new Tag("div").clazz("hardware").content(t("Hardware"));
|
Tag tileMenu = new Tag("div").clazz("hardware").content(t("Hardware"));
|
||||||
Tag list = new Tag("div").clazz("list").content("");
|
Tag list = new Tag("div").clazz("list").content("");
|
||||||
@@ -237,14 +336,26 @@ public class Plan implements Constants{
|
|||||||
return list.addTo(tileMenu);
|
return list.addTo(tileMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepares the hardware div of the plan
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private Tag heartbeat() {
|
private Tag heartbeat() {
|
||||||
return new Div("heartbeat").content("");
|
return new Div("heartbeat").content("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send a heatbeat to the client
|
||||||
|
*/
|
||||||
public void heatbeat() {
|
public void heatbeat() {
|
||||||
stream("heartbeat @ "+new Date().getTime());
|
stream("heartbeat @ "+new Date().getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generates a html document of this plan
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public Page html() throws IOException {
|
public Page html() throws IOException {
|
||||||
Page page = new Page().append("<div id=\"plan\">");
|
Page page = new Page().append("<div id=\"plan\">");
|
||||||
for (Tile tile: tiles.values()) {
|
for (Tile tile: tiles.values()) {
|
||||||
@@ -261,6 +372,19 @@ public class Plan implements Constants{
|
|||||||
.js("js/plan.js");
|
.js("js/plan.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* loads a track layout from a file, along with its assigned cars, trains, routes and control unit settings
|
||||||
|
* @param filename
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
* @throws InstantiationException
|
||||||
|
* @throws IllegalAccessException
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
* @throws InvocationTargetException
|
||||||
|
* @throws NoSuchMethodException
|
||||||
|
* @throws SecurityException
|
||||||
|
*/
|
||||||
public static Plan load(String filename) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
public static Plan load(String filename) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
||||||
Plan plan = new Plan();
|
Plan plan = new Plan();
|
||||||
try {
|
try {
|
||||||
@@ -292,6 +416,11 @@ public class Plan implements Constants{
|
|||||||
return plan;
|
return plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates the main menu attached to the plan
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private Tag menu() throws IOException {
|
private Tag menu() throws IOException {
|
||||||
Tag menu = new Tag("div").clazz("menu");
|
Tag menu = new Tag("div").clazz("menu");
|
||||||
new Tag("div").clazz("emergency").content(t("Emergency")).attr("onclick","return request({realm:'"+REALM_CU+"',action:'"+ACTION_EMERGENCY+"'});").addTo(menu);
|
new Tag("div").clazz("emergency").content(t("Emergency")).attr("onclick","return request({realm:'"+REALM_CU+"',action:'"+ACTION_EMERGENCY+"'});").addTo(menu);
|
||||||
@@ -303,10 +432,18 @@ public class Plan implements Constants{
|
|||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepares the messages div of the plan
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private Tag messages() {
|
private Tag messages() {
|
||||||
return new Div("messages").content("");
|
return new Div("messages").content("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates the move-tile menu of the plan
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private Tag moveMenu() {
|
private Tag moveMenu() {
|
||||||
Tag tileMenu = new Tag("div").clazz("move").title(t("Move tiles")).content(t("↹"));
|
Tag tileMenu = new Tag("div").clazz("move").title(t("Move tiles")).content(t("↹"));
|
||||||
Tag tiles = new Tag("div").clazz("list").content("");
|
Tag tiles = new Tag("div").clazz("list").content("");
|
||||||
@@ -317,6 +454,14 @@ public class Plan implements Constants{
|
|||||||
return tiles.addTo(tileMenu);
|
return tiles.addTo(tileMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* processes move-tile instructions sent from the client
|
||||||
|
* @param direction
|
||||||
|
* @param tileId
|
||||||
|
* @return
|
||||||
|
* @throws NumberFormatException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private String moveTile(String direction, String tileId) throws NumberFormatException, IOException {
|
private String moveTile(String direction, String tileId) throws NumberFormatException, IOException {
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
case "south":
|
case "south":
|
||||||
@@ -331,6 +476,13 @@ public class Plan implements Constants{
|
|||||||
throw new InvalidParameterException(t("\"{}\" is not a known direction!"));
|
throw new InvalidParameterException(t("\"{}\" is not a known direction!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* processes move-tile instructions sent from the client (subroutine)
|
||||||
|
* @param tile
|
||||||
|
* @param direction
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private String moveTile(Tile tile, Direction direction) throws IOException {
|
private String moveTile(Tile tile, Direction direction) throws IOException {
|
||||||
boolean moved = false;
|
boolean moved = false;
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
@@ -353,6 +505,14 @@ public class Plan implements Constants{
|
|||||||
return t(moved ? "Tile(s) moved.":"No tile(s) moved.");
|
return t(moved ? "Tile(s) moved.":"No tile(s) moved.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* processes move-tile instructions sent from the client (subroutine)
|
||||||
|
* @param tile
|
||||||
|
* @param xstep
|
||||||
|
* @param ystep
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private boolean moveTile(Tile tile,int xstep,int ystep) throws IOException {
|
private boolean moveTile(Tile tile,int xstep,int ystep) throws IOException {
|
||||||
LOG.error("moveTile({} +{}/+{})",tile,xstep,ystep);
|
LOG.error("moveTile({} +{}/+{})",tile,xstep,ystep);
|
||||||
Stack<Tile> stack = new Stack<Tile>();
|
Stack<Tile> stack = new Stack<Tile>();
|
||||||
@@ -372,29 +532,53 @@ public class Plan implements Constants{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a new tile to the plan on the client side
|
||||||
|
* @param tile
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public Tile place(Tile tile) throws IOException {
|
public Tile place(Tile tile) throws IOException {
|
||||||
stream("place "+tile.tag(null));
|
stream("place "+tile.tag(null));
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a command to the control unit's command queue
|
||||||
|
* @param command
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Command queue(Command command) {
|
public Command queue(Command command) {
|
||||||
return controlUnit.queue(command);
|
return controlUnit.queue(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a new route to the plan
|
||||||
|
* @param route
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
Route registerRoute(Route route) {
|
Route registerRoute(Route route) {
|
||||||
for (Tile tile: route.path()) tile.add(route);
|
for (Tile tile: route.path()) tile.add(route);
|
||||||
routes.put(route.id(), route);
|
routes.put(route.id(), route);
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes a tile from the track layout
|
||||||
|
* @param tile
|
||||||
|
*/
|
||||||
private void remove(Tile tile) {
|
private void remove(Tile tile) {
|
||||||
remove_intern(tile.x,tile.y);
|
removeTile(tile.x,tile.y);
|
||||||
if (tile instanceof Block) blocks.remove(tile);
|
if (tile instanceof Block) blocks.remove(tile);
|
||||||
for (int i=1; i<tile.len(); i++) remove_intern(tile.x+i, tile.y); // remove shadow tiles
|
for (int i=1; i<tile.len(); i++) removeTile(tile.x+i, tile.y); // remove shadow tiles
|
||||||
for (int i=1; i<tile.height(); i++) remove_intern(tile.x, tile.y+i); // remove shadow tiles
|
for (int i=1; i<tile.height(); i++) removeTile(tile.x, tile.y+i); // remove shadow tiles
|
||||||
if (tile != null) stream("remove "+tile.id());
|
if (tile != null) stream("remove "+tile.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes a route from the track layout
|
||||||
|
* @param route
|
||||||
|
*/
|
||||||
public void remove(Route route) {
|
public void remove(Route route) {
|
||||||
for (Tile tile : route.path()) tile.remove(route);
|
for (Tile tile : route.path()) tile.remove(route);
|
||||||
for (Train train : Train.list()) {
|
for (Train train : Train.list()) {
|
||||||
@@ -404,10 +588,20 @@ public class Plan implements Constants{
|
|||||||
stream(t("Removed {}.",route));
|
stream(t("Removed {}.",route));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void remove_intern(int x, int y) {
|
/**
|
||||||
|
* removes a tile from the track layout (subroutine)
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
*/
|
||||||
|
private void removeTile(int x, int y) {
|
||||||
LOG.debug("removed {} from tile list",tiles.remove(Tile.id(x, y)));
|
LOG.debug("removed {} from tile list",tiles.remove(Tile.id(x, y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a specific route from the list of routes assigned to this plan
|
||||||
|
* @param routeId the id of the route requestd
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Route route(int routeId) {
|
public Route route(int routeId) {
|
||||||
return routes.get(routeId);
|
return routes.get(routeId);
|
||||||
}
|
}
|
||||||
@@ -425,6 +619,12 @@ public class Plan implements Constants{
|
|||||||
return t("Unknown action: {}",params.get(ACTION));
|
return t("Unknown action: {}",params.get(ACTION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* saves the plan to a set of files, along with its cars, tiles, trains, routes and control unit settings
|
||||||
|
* @param name
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private String saveTo(String name) throws IOException {
|
private String saveTo(String name) throws IOException {
|
||||||
if (name == null || name.isEmpty()) throw new NullPointerException("Name must not be empty!");
|
if (name == null || name.isEmpty()) throw new NullPointerException("Name must not be empty!");
|
||||||
Car.saveAll(name+".cars");
|
Car.saveAll(name+".cars");
|
||||||
@@ -435,20 +635,38 @@ public class Plan implements Constants{
|
|||||||
return t("Plan saved as \"{}\".",name);
|
return t("Plan saved as \"{}\".",name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds a tile to the plan at a specific position
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @param tile
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void set(int x,int y,Tile tile) throws IOException {
|
public void set(int x,int y,Tile tile) throws IOException {
|
||||||
if (tile == null) return;
|
if (tile == null) return;
|
||||||
if (tile instanceof Block) blocks.add((Block) tile);
|
if (tile instanceof Block) blocks.add((Block) tile);
|
||||||
for (int i=1; i<tile.len(); i++) set(x+i,y,new Shadow(tile));
|
for (int i=1; i<tile.len(); i++) set(x+i,y,new Shadow(tile));
|
||||||
for (int i=1; i<tile.height(); i++) set(x,y+i,new Shadow(tile));
|
for (int i=1; i<tile.height(); i++) set(x,y+i,new Shadow(tile));
|
||||||
set_intern(x,y,tile);
|
setIntern(x,y,tile);
|
||||||
place(tile);
|
place(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void set_intern(int x, int y, Tile tile) {
|
/**
|
||||||
|
* adds a tile to the plan at a specific position (subroutine)
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @param tile
|
||||||
|
*/
|
||||||
|
private void setIntern(int x, int y, Tile tile) {
|
||||||
tile.position(x, y).plan(this);
|
tile.position(x, y).plan(this);
|
||||||
tiles.put(tile.id(),tile);
|
tiles.put(tile.id(),tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shows the properties of an entity specified in the params.context value
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Window showContext(HashMap<String, String> params) {
|
public Window showContext(HashMap<String, String> params) {
|
||||||
String[] parts = params.get(CONTEXT).split(":");
|
String[] parts = params.get(CONTEXT).split(":");
|
||||||
String realm = parts[0];
|
String realm = parts[0];
|
||||||
@@ -460,6 +678,10 @@ public class Plan implements Constants{
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends some data to the clients
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
public synchronized void stream(String data) {
|
public synchronized void stream(String data) {
|
||||||
data = data.replaceAll("\n", "").replaceAll("\r", "");
|
data = data.replaceAll("\n", "").replaceAll("\r", "");
|
||||||
//if (!data.startsWith("heartbeat")) LOG.debug("streaming: {}",data);
|
//if (!data.startsWith("heartbeat")) LOG.debug("streaming: {}",data);
|
||||||
@@ -488,10 +710,21 @@ public class Plan implements Constants{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shorthand for Translations.get(message,fills)
|
||||||
|
* @param message
|
||||||
|
* @param fills
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private String t(String message, Object...fills) {
|
private String t(String message, Object...fills) {
|
||||||
return Translation.get(Application.class, message, fills);
|
return Translation.get(Application.class, message, fills);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generates the menu for selecting tiles to be added to the layout
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private Tag tileMenu() throws IOException {
|
private Tag tileMenu() throws IOException {
|
||||||
Tag tileMenu = new Tag("div").clazz("addtile").title(t("Add tile")).content("╦");
|
Tag tileMenu = new Tag("div").clazz("addtile").title(t("Add tile")).content("╦");
|
||||||
|
|
||||||
@@ -529,6 +762,11 @@ public class Plan implements Constants{
|
|||||||
return tiles.addTo(tileMenu);
|
return tiles.addTo(tileMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generates the train menu
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private Tag trainMenu() throws IOException {
|
private Tag trainMenu() throws IOException {
|
||||||
Tag tileMenu = new Tag("div").clazz("trains").content(t("Trains"));
|
Tag tileMenu = new Tag("div").clazz("trains").content(t("Trains"));
|
||||||
Tag tiles = new Tag("div").clazz("list").content("");
|
Tag tiles = new Tag("div").clazz("list").content("");
|
||||||
@@ -537,10 +775,21 @@ public class Plan implements Constants{
|
|||||||
return tiles.addTo(tileMenu);
|
return tiles.addTo(tileMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updates a tile
|
||||||
|
* @param tile
|
||||||
|
* @param params
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
private Tile update(Tile tile, HashMap<String, String> params) throws IOException {
|
private Tile update(Tile tile, HashMap<String, String> params) throws IOException {
|
||||||
return tile == null ? null : tile.update(params);
|
return tile == null ? null : tile.update(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a Ghost train warning to the client
|
||||||
|
* @param contact
|
||||||
|
*/
|
||||||
public void warn(Contact contact) {
|
public void warn(Contact contact) {
|
||||||
stream(t("Warning: {}",t("Ghost train @ {}",contact)));
|
stream(t("Warning: {}",t("Ghost train @ {}",contact)));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user