001package jmri.server.json.message; 002 003import static jmri.server.json.message.JsonMessage.CLIENT; 004 005import com.fasterxml.jackson.databind.JsonNode; 006import com.fasterxml.jackson.databind.node.ArrayNode; 007import com.fasterxml.jackson.databind.node.ObjectNode; 008import java.io.IOException; 009import java.util.Set; 010import java.util.UUID; 011import javax.servlet.http.HttpServletResponse; 012import jmri.InstanceManager; 013import jmri.JmriException; 014import jmri.server.json.JSON; 015import jmri.server.json.JsonConnection; 016import jmri.server.json.JsonException; 017import jmri.server.json.JsonRequest; 018import jmri.server.json.JsonSocketService; 019 020/** 021 * 022 * @author Randall Wood Copyright 2017, 2019 023 */ 024public class JsonMessageSocketService extends JsonSocketService<JsonMessageHttpService> { 025 026 public JsonMessageSocketService(JsonConnection connection) { 027 super(connection, new JsonMessageHttpService(connection.getObjectMapper())); 028 } 029 030 @Override 031 public void onMessage(String type, JsonNode data, JsonRequest request) 032 throws IOException, JmriException, JsonException { 033 switch (type) { 034 case JSON.HELLO: 035 if (!data.path(CLIENT).isMissingNode()) { 036 String client = data.path(CLIENT).asText(); 037 if (!client.isEmpty()) { 038 subscribe(client, request.id); 039 } else { 040 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 041 Bundle.getMessage(request.locale, "ErrorEmptyAttribute", JsonMessage.CLIENT, type), request.id); 042 } 043 } 044 break; 045 case JsonMessage.CLIENT: 046 switch (request.method) { 047 case JSON.DELETE: 048 // remove client id 049 if (!data.path(CLIENT).isMissingNode()) { 050 String client = data.path(CLIENT).asText(); 051 if (!client.isEmpty()) { 052 getManager().unsubscribe(client); 053 } else { 054 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 055 Bundle.getMessage(request.locale, "ErrorEmptyAttribute", JsonMessage.CLIENT, type), request.id); 056 } 057 } else { 058 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 059 Bundle.getMessage(request.locale, "ErrorMissingAttribute", JsonMessage.CLIENT, type), request.id); 060 } 061 break; 062 case JSON.GET: 063 // if client is not specified, and connection is not subscribing, create a client id for it 064 // if client is not specified, and connection is subscribing, return onList results 065 // if client is specified, and not empty, throw JsonException if client 066 // is not for this connection, otherwise return client 067 // if client is specified, and empty, return first client for connection 068 if (!data.path(CLIENT).isMissingNode()) { 069 String client = data.path(CLIENT).asText(); 070 if (!client.isEmpty()) { 071 if (getManager().getClients(connection).contains(client)) { 072 connection.sendMessage(getClient(client, request), request.id); 073 } else { 074 throw new JsonException(HttpServletResponse.SC_NOT_FOUND, 075 Bundle.getMessage(request.locale, "MessageClientNotForThisConnection", client), request.id); 076 } 077 } else { 078 connection.sendMessage(getClient(getManager().getClient(connection), request), request.id); 079 } 080 } else { 081 if (getManager().getClients(connection).isEmpty()) { 082 String client = UUID.randomUUID().toString(); 083 subscribe(client, request.id); 084 connection.sendMessage(getClient(client, request), request.id); 085 } else { 086 onList(type, data, request); 087 } 088 } 089 break; 090 case JSON.POST: 091 case JSON.PUT: 092 default: 093 // add client using client-provided id 094 if (!data.path(CLIENT).isMissingNode()) { 095 String client = data.path(CLIENT).asText(); 096 if (!client.isEmpty()) { 097 subscribe(client, request.id); 098 } else { 099 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 100 Bundle.getMessage(request.locale, "ErrorEmptyAttribute", JsonMessage.CLIENT, type), request.id); 101 } 102 } else { 103 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 104 Bundle.getMessage(request.locale, "ErrorMissingAttribute", JsonMessage.CLIENT, type), request.id); 105 } 106 break; 107 } 108 break; // break inside gets to here, then this goes out 109 default: 110 // ignore anything else 111 break; 112 } 113 } 114 115 @Override 116 public void onList(String type, JsonNode data, JsonRequest request) throws IOException, JmriException, JsonException { 117 switch (type) { 118 case JSON.HELLO: 119 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 120 Bundle.getMessage(request.locale, "UnlistableService", type), request.id); 121 case JsonMessage.CLIENT: 122 Set<String> clients = getManager().getClients(connection); 123 if (clients.isEmpty()) { 124 throw new JsonException(HttpServletResponse.SC_NOT_FOUND, 125 Bundle.getMessage(request.locale, "NoMessageClientForThisConnection", type), request.id); 126 } 127 ArrayNode array = service.getObjectMapper().createArrayNode(); 128 for (String client : clients) { 129 array.add(getClient(client, request)); 130 } 131 connection.sendMessage(service.message(array, request.id), request.id); 132 break; 133 default: 134 // silently ignore 135 } 136 } 137 138 @Override 139 public void onClose() { 140 getManager().unsubscribe(this.connection); 141 } 142 143 private JsonNode getClient(String client, JsonRequest request) throws JsonException { 144 if (client == null) { 145 throw new JsonException(HttpServletResponse.SC_NOT_FOUND, 146 Bundle.getMessage(request.locale, "NoMessageClientForThisConnection"), request.id); 147 } 148 ObjectNode root = this.connection.getObjectMapper().createObjectNode(); 149 root.put(JSON.TYPE, JsonMessage.CLIENT); 150 ObjectNode data = root.putObject(JSON.DATA); 151 data.put(JsonMessage.CLIENT, client); 152 return root; 153 } 154 155 private void subscribe(String client, int id) throws JsonException { 156 try { 157 getManager().subscribe(client, this.connection); 158 } catch (IllegalArgumentException ex) { 159 throw new JsonException(HttpServletResponse.SC_CONFLICT, 160 Bundle.getMessage(this.connection.getLocale(), "ErrorClientConflict", CLIENT), id); 161 } 162 } 163 164 private JsonMessageClientManager getManager() { 165 return InstanceManager.getDefault(JsonMessageClientManager.class); 166 } 167}