001package jmri.server.json.power; 002 003import static jmri.server.json.JSON.DEFAULT; 004import static jmri.server.json.JSON.NAME; 005import static jmri.server.json.JSON.OFF; 006import static jmri.server.json.JSON.ON; 007import static jmri.server.json.JSON.PREFIX; 008import static jmri.server.json.JSON.STATE; 009import static jmri.server.json.JSON.UNKNOWN; 010import static jmri.server.json.power.JsonPowerServiceFactory.POWER; 011 012import com.fasterxml.jackson.databind.JsonNode; 013import com.fasterxml.jackson.databind.ObjectMapper; 014import com.fasterxml.jackson.databind.node.ArrayNode; 015import com.fasterxml.jackson.databind.node.ObjectNode; 016import javax.annotation.CheckForNull; 017import javax.servlet.http.HttpServletResponse; 018import jmri.InstanceManager; 019import jmri.JmriException; 020import jmri.PowerManager; 021import jmri.SystemConnectionMemo; 022import jmri.jmrix.SystemConnectionMemoManager; 023import jmri.server.json.JsonException; 024import jmri.server.json.JsonHttpService; 025import jmri.server.json.JsonRequest; 026 027/** 028 * @author Randall Wood Copyright 2016, 2018 029 */ 030public class JsonPowerHttpService extends JsonHttpService { 031 032 public JsonPowerHttpService(ObjectMapper mapper) { 033 super(mapper); 034 } 035 036 @Override 037 // Nullable to override inherited NonNull requirement 038 public JsonNode doGet(String type, @CheckForNull String name, JsonNode parameters, JsonRequest request) 039 throws JsonException { 040 ObjectNode data = mapper.createObjectNode(); 041 PowerManager manager = resolvePowerManager(name, parameters, request); 042 if (manager != null) { 043 data.put(NAME, manager.getUserName()); 044 switch (manager.getPower()) { 045 case PowerManager.OFF: 046 data.put(STATE, OFF); 047 break; 048 case PowerManager.ON: 049 data.put(STATE, ON); 050 break; 051 default: 052 data.put(STATE, UNKNOWN); 053 break; 054 } 055 data.put(DEFAULT, manager.equals(InstanceManager.getDefault(PowerManager.class))); 056 String managerPrefix = getPrefixForManager(manager); 057 if (managerPrefix != null) { 058 data.put(PREFIX, managerPrefix); 059 } 060 } else { 061 // No PowerManager is defined; just report it as UNKNOWN 062 data.put(STATE, UNKNOWN); 063 data.put(NAME, ""); 064 data.put(DEFAULT, false); 065 } 066 return message(POWER, data, request.id); 067 } 068 069 @Override 070 public JsonNode doPost(String type, String name, JsonNode data, JsonRequest request) throws JsonException { 071 int state = data.path(STATE).asInt(UNKNOWN); 072 if (state != UNKNOWN) { 073 try { 074 PowerManager manager = resolvePowerManager(name, data, request); 075 if (manager != null) { 076 switch (state) { 077 case OFF: 078 manager.setPower(PowerManager.OFF); 079 break; 080 case ON: 081 manager.setPower(PowerManager.ON); 082 break; 083 default: 084 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 085 Bundle.getMessage(request.locale, "ErrorUnknownState", POWER, state), request.id); 086 } 087 } 088 } catch (JmriException ex) { 089 throw new JsonException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex, request.id); 090 } 091 } 092 return this.doGet(type, name, data, request); 093 } 094 095 /** 096 * Resolves the PowerManager to use for a request. Checks for a 097 * {@code prefix} field in {@code data} first (connection-specific routing), 098 * then falls back to matching by {@code name} (user name), then falls back 099 * to the default PowerManager. When {@code prefix} is present but does not 100 * match a known connection, throws a {@link JsonException} with HTTP 400. 101 * 102 * @param name the power manager user name, or empty/null for default 103 * @param data the JSON data node; may contain an optional {@code prefix} field 104 * @param request the originating request, used for locale and id in error messages 105 * @return the resolved PowerManager, or null if none is configured 106 * @throws JsonException if a prefix is supplied but does not match any known connection 107 */ 108 @CheckForNull 109 private PowerManager resolvePowerManager(@CheckForNull String name, JsonNode data, JsonRequest request) 110 throws JsonException { 111 String prefix = data.path(PREFIX).asText(); 112 if (!prefix.isEmpty()) { 113 SystemConnectionMemo memo = SystemConnectionMemoManager.getDefault() 114 .getSystemConnectionMemoForSystemPrefix(prefix); 115 if (memo != null && memo.provides(PowerManager.class)) { 116 return memo.get(PowerManager.class); 117 } 118 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 119 Bundle.getMessage(request.locale, "ErrorUnknownPrefix", prefix), request.id); 120 } 121 if (name != null && !name.isEmpty()) { 122 for (PowerManager pm : InstanceManager.getList(PowerManager.class)) { 123 if (pm.getUserName().equals(name)) { 124 return pm; 125 } 126 } 127 } 128 return InstanceManager.getNullableDefault(PowerManager.class); 129 } 130 131 /** 132 * Returns the system prefix of the connection that provides the given 133 * PowerManager, or null if no connection can be found for it. 134 * 135 * @param manager the PowerManager to look up 136 * @return system prefix string, or null 137 */ 138 @CheckForNull 139 private String getPrefixForManager(PowerManager manager) { 140 for (SystemConnectionMemo memo : InstanceManager.getList(SystemConnectionMemo.class)) { 141 if (memo.provides(PowerManager.class) && manager.equals(memo.get(PowerManager.class))) { 142 return memo.getSystemPrefix(); 143 } 144 } 145 return null; 146 } 147 148 @Override 149 public JsonNode doGetList(String type, JsonNode data, JsonRequest request) throws JsonException { 150 ArrayNode array = this.mapper.createArrayNode(); 151 for (PowerManager manager : InstanceManager.getList(PowerManager.class)) { 152 array.add(this.doGet(type, manager.getUserName(), data, request)); 153 } 154 return message(array, request.id); 155 } 156 157 @Override 158 public JsonNode doSchema(String type, boolean server, JsonRequest request) throws JsonException { 159 if (POWER.equals(type)) { 160 return doSchema(type, 161 server, 162 "jmri/server/json/power/power-server.json", 163 "jmri/server/json/power/power-client.json", 164 request.id); 165 } else { 166 throw new JsonException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 167 Bundle.getMessage(request.locale, JsonException.ERROR_UNKNOWN_TYPE, type), request.id); 168 } 169 } 170}