001package jmri.server.json.schema;
002
003import com.fasterxml.jackson.databind.JsonNode;
004import com.fasterxml.jackson.databind.ObjectMapper;
005import com.fasterxml.jackson.databind.node.ArrayNode;
006import com.fasterxml.jackson.databind.node.ObjectNode;
007import java.util.HashSet;
008import java.util.Set;
009import javax.servlet.http.HttpServletResponse;
010import jmri.InstanceManager;
011import jmri.server.json.JSON;
012import jmri.server.json.JsonException;
013import jmri.server.json.JsonHttpService;
014import jmri.server.json.JsonRequest;
015
016/**
017 * Service to support getting core JSON Schemas for the JSON Server.
018 *
019 * @author Randall Wood Copyright 2018
020 */
021public class JsonSchemaHttpService extends JsonHttpService {
022
023    JsonSchemaHttpService(ObjectMapper mapper) {
024        super(mapper);
025    }
026
027    @Override
028    public JsonNode doGet(String type, String name, JsonNode data, JsonRequest request) throws JsonException {
029        // note use of Boolean for tristate null, true, false
030        // if server == null, returns both schemas in an array
031        // if server != null, returns single schema for client or server as
032        // appropriate
033        Boolean server = null;
034        if (data.path(JSON.SERVER).isBoolean()) {
035            server = data.path(JSON.SERVER).asBoolean();
036        }
037        if (data.path(JSON.CLIENT).isBoolean()) {
038            if (server == null) {
039                server = !data.path(JSON.CLIENT).asBoolean();
040            } else if (Boolean.TRUE.equals(server)) {
041                server = null; // server and client are true
042            }
043        }
044        switch (type) {
045            case JSON.SCHEMA:
046                if (JSON.JSON.equals(name)) {
047                    if (server != null) {
048                        return this.doSchema(JSON.JSON, server, request);
049                    }
050                    return message(mapper.createArrayNode()
051                            .add(this.doSchema(JSON.JSON, true, request))
052                            .add(this.doSchema(JSON.JSON, false, request)),
053                            request.id);
054                } else {
055                    try {
056                        ArrayNode schemas = this.mapper.createArrayNode();
057                        Set<JsonNode> dedup = new HashSet<>();
058                        for (JsonHttpService service : InstanceManager.getDefault(JsonSchemaServiceCache.class)
059                                .getServices(name, request.version)) {
060                            if (server == null || server) {
061                                this.doSchema(schemas, dedup, service, name, true, request);
062                            }
063                            if (server == null || !server) {
064                                this.doSchema(schemas, dedup, service, name, false, request);
065                            }
066                        }
067                        // return single object if only one, otherwise return
068                        // complete array
069                        if (schemas.size() == 1) {
070                            return schemas.get(0);
071                        }
072                        return message(schemas, request.id);
073                    } catch (NullPointerException ex) {
074                        throw new JsonException(HttpServletResponse.SC_BAD_REQUEST,
075                                Bundle.getMessage(request.locale, JsonException.ERROR_UNKNOWN_TYPE, name), ex, request.id);
076                    }
077                }
078            case JSON.TYPE:
079                if (InstanceManager.getDefault(JsonSchemaServiceCache.class).getTypes(request.version).contains(name)) {
080                    ObjectNode payload = this.mapper.createObjectNode();
081                    payload.put(JSON.NAME, name);
082                    payload.put(JSON.SERVER,
083                            InstanceManager.getDefault(JsonSchemaServiceCache.class).getServerTypes(request.version).contains(name));
084                    payload.put(JSON.CLIENT,
085                            InstanceManager.getDefault(JsonSchemaServiceCache.class).getClientTypes(request.version).contains(name));
086                    return message(JSON.TYPE, payload, request.id);
087                } else {
088                    throw new JsonException(HttpServletResponse.SC_NOT_FOUND,
089                            Bundle.getMessage(request.locale, JsonException.ERROR_NOT_FOUND, type, name), request.id);
090                }
091            default:
092                throw new JsonException(HttpServletResponse.SC_BAD_REQUEST,
093                        Bundle.getMessage(request.locale, JsonException.ERROR_UNKNOWN_TYPE, type), request.id);
094        }
095    }
096
097    @Override
098    public JsonNode doPost(String type, String name, JsonNode data, JsonRequest request) throws JsonException {
099        throw new JsonException(HttpServletResponse.SC_METHOD_NOT_ALLOWED,
100                Bundle.getMessage(request.locale, "PostNotAllowed", type), request.id);
101    }
102
103    @Override
104    public JsonNode doGetList(String type, JsonNode parameters, JsonRequest request) throws JsonException {
105        if (JSON.TYPE.equals(type)) {
106            ArrayNode array = this.mapper.createArrayNode();
107            JsonNode data = this.mapper.createObjectNode();
108            for (String name : InstanceManager.getDefault(JsonSchemaServiceCache.class).getTypes(request.version)) {
109                array.add(this.doGet(type, name, data, request));
110            }
111            return message(array, request.id);
112        } else {
113            throw new JsonException(HttpServletResponse.SC_BAD_REQUEST,
114                    Bundle.getMessage(request.locale, "UnlistableService", type), request.id);
115        }
116    }
117
118    @Override
119    public JsonNode doSchema(String type, boolean server, JsonRequest request) throws JsonException {
120        switch (type) {
121            case JSON.JSON:
122            case JSON.SCHEMA:
123            case JSON.TYPE:
124                return doSchema(type,
125                        server,
126                        "jmri/server/json/schema/" + type + "-server.json",
127                        "jmri/server/json/schema/" + type + "-client.json",
128                        request.id);
129            default:
130                throw new JsonException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
131                        Bundle.getMessage(request.locale, JsonException.ERROR_UNKNOWN_TYPE, type), request.id);
132        }
133    }
134    
135    private void doSchema(ArrayNode schemas, Set<JsonNode> dedup, JsonHttpService service, String name, boolean server, JsonRequest request) throws JsonException {
136        try {
137            JsonNode schema = service.doSchema(name, server, request);
138            if (!dedup.contains(schema)) {
139                schemas.add(schema);
140                dedup.add(schema);
141            }
142        } catch (JsonException ex) {
143            if (ex.getCode() != HttpServletResponse.SC_BAD_REQUEST) {
144                throw ex;
145            }
146        }
147    }
148}