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}