001package jmri.server.json.util;
002
003import com.fasterxml.jackson.databind.JsonNode;
004import java.beans.PropertyChangeEvent;
005import java.beans.PropertyChangeListener;
006import java.io.IOException;
007import jmri.InstanceManager;
008import jmri.JmriException;
009import jmri.server.json.JSON;
010import jmri.server.json.JsonConnection;
011import jmri.server.json.JsonException;
012import jmri.server.json.JsonRequest;
013import jmri.server.json.JsonSocketService;
014import jmri.web.server.WebServerPreferences;
015import org.slf4j.Logger;
016import org.slf4j.LoggerFactory;
017
018/**
019 *
020 * @author Randall Wood
021 */
022public class JsonUtilSocketService extends JsonSocketService<JsonUtilHttpService> {
023
024    private PropertyChangeListener rrNameListener;
025    private static final Logger log = LoggerFactory.getLogger(JsonUtilSocketService.class);
026
027    public JsonUtilSocketService(JsonConnection connection) {
028        super(connection, new JsonUtilHttpService(connection.getObjectMapper()));
029    }
030
031    /**
032     * Package protected method for unit testing that allows a test HTTP service
033     * to be used.
034     * 
035     * @param connection the connection to use
036     * @param service    the supporting HTTP service
037     */
038    JsonUtilSocketService(JsonConnection connection, JsonUtilHttpService service) {
039        super(connection, service);
040    }
041
042    @Override
043    public void onMessage(String type, JsonNode data, JsonRequest request) throws IOException, JmriException, JsonException {
044        String name = data.path(JSON.NAME).asText();
045        switch (type) {
046            case JSON.LOCALE:
047                // do nothing - we only want to prevent an error at this point
048                break;
049            case JSON.PING:
050                this.connection.sendMessage(this.connection.getObjectMapper().createObjectNode().put(JSON.TYPE, JSON.PONG), request.id);
051                break;
052            case JSON.GOODBYE:
053                this.connection.sendMessage(this.connection.getObjectMapper().createObjectNode().put(JSON.TYPE, JSON.GOODBYE), request.id);
054                break;
055            case JSON.RAILROAD:
056                this.onRailroadNameMessage(type, data, request);
057                break;
058            default:
059                this.connection.sendMessage(this.service.doPost(type, name, data, request), request.id);
060                break;
061        }
062    }
063
064    private void onRailroadNameMessage(String type, JsonNode data, JsonRequest request) throws IOException, JmriException, JsonException {
065        String name = data.path(JSON.NAME).asText();
066        // Follow up handling a POST (change railroad name command) with the same answer as a GET (ask)
067        if (request.method.equals(JSON.POST)) {
068            log.debug("Processing change railroad name to {} from socket service", name);
069            this.connection.sendMessage(this.service.doPost(type, name, data, request), request.id);
070        }
071        this.connection.sendMessage(this.service.doGet(type, name, data, request), request.id);
072        this.rrNameListener = (PropertyChangeEvent evt) -> {
073            try {
074                this.handleRailroadChange();
075            } catch (IOException ex) {
076                InstanceManager.getDefault(WebServerPreferences.class).removePropertyChangeListener(this.rrNameListener);
077            }
078        };
079        InstanceManager.getOptionalDefault(WebServerPreferences.class).ifPresent(preferences -> preferences.addPropertyChangeListener(this.rrNameListener));
080    }
081
082    @Override
083    public void onList(String type, JsonNode data, JsonRequest request) throws IOException, JmriException, JsonException {
084        this.connection.sendMessage(this.service.doGetList(type, data, request), request.id);
085    }
086
087    @Override
088    public void onClose() {
089        InstanceManager.getOptionalDefault(WebServerPreferences.class).ifPresent(preferences -> preferences.removePropertyChangeListener(this.rrNameListener));
090    }
091
092    private void handleRailroadChange() throws IOException {
093        try {
094            connection.sendMessage(service.doGet(JSON.RAILROAD, null, connection.getObjectMapper().createObjectNode(), new JsonRequest(this.connection.getLocale(), JSON.V5, JSON.GET, 0)), 0);
095        } catch (JsonException ex) {
096            this.connection.sendMessage(ex.getJsonMessage(), 0);
097        }
098    }
099}