001package jmri.server.json.util; 002 003import static jmri.server.json.JSON.CONTROL_PANEL; 004import static jmri.server.json.JSON.LAYOUT_PANEL; 005import static jmri.server.json.JSON.NAME; 006import static jmri.server.json.JSON.PANEL; 007import static jmri.server.json.JSON.PANEL_PANEL; 008import static jmri.server.json.JSON.SWITCHBOARD_PANEL; 009import static jmri.server.json.JSON.TYPE; 010import static jmri.server.json.JSON.URL; 011import static jmri.server.json.JSON.USERNAME; 012 013import com.fasterxml.jackson.databind.JsonNode; 014import com.fasterxml.jackson.databind.ObjectMapper; 015import com.fasterxml.jackson.databind.node.ArrayNode; 016import com.fasterxml.jackson.databind.node.ObjectNode; 017 018import java.io.IOException; 019import java.lang.reflect.Field; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.Enumeration; 023import java.util.Locale; 024import java.util.Objects; 025 026import javax.annotation.CheckForNull; 027import javax.annotation.Nonnull; 028import javax.servlet.http.HttpServletResponse; 029import javax.swing.JFrame; 030 031import jmri.DccLocoAddress; 032import jmri.InstanceManager; 033import jmri.Metadata; 034import jmri.server.json.JsonServerPreferences; 035import jmri.jmrit.display.Editor; 036import jmri.jmrit.display.EditorManager; 037import jmri.jmrit.display.controlPanelEditor.ControlPanelEditor; 038import jmri.jmrit.display.layoutEditor.LayoutEditor; 039import jmri.jmrit.display.switchboardEditor.SwitchboardEditor; 040import jmri.jmrix.ConnectionConfig; 041import jmri.jmrix.ConnectionConfigManager; 042import jmri.SystemConnectionMemo; 043import jmri.jmrix.internal.InternalSystemConnectionMemo; 044import jmri.profile.Profile; 045import jmri.profile.ProfileManager; 046import jmri.server.json.JSON; 047import jmri.server.json.JsonException; 048import jmri.server.json.JsonHttpService; 049import jmri.server.json.JsonRequest; 050import jmri.util.node.NodeIdentity; 051import jmri.util.zeroconf.ZeroConfService; 052import jmri.util.zeroconf.ZeroConfServiceManager; 053import jmri.web.server.WebServerPreferences; 054import org.slf4j.Logger; 055import org.slf4j.LoggerFactory; 056 057/** 058 * @author Randall Wood Copyright 2016, 2017, 2018 059 */ 060public class JsonUtilHttpService extends JsonHttpService { 061 062 private static final String RESOURCE_PATH = "jmri/server/json/util/"; 063 private static final Logger log = LoggerFactory.getLogger(JsonUtilHttpService.class); 064 065 public JsonUtilHttpService(ObjectMapper mapper) { 066 super(mapper); 067 } 068 069 @Override 070 // use @CheckForNull to override @Nonnull specified in superclass 071 public JsonNode doGet(String type, @CheckForNull String name, JsonNode data, JsonRequest request) 072 throws JsonException { 073 switch (type) { 074 case JSON.HELLO: 075 return this.getHello( 076 InstanceManager.getDefault(JsonServerPreferences.class).getHeartbeatInterval(), request); 077 case JSON.METADATA: 078 if (name == null) { 079 return this.getMetadata(request); 080 } 081 return this.getMetadata(request.locale, name, request.id); 082 case JSON.NETWORK_SERVICE: 083 case JSON.NETWORK_SERVICES: 084 if (name == null) { 085 return this.getNetworkServices(request.locale, request.id); 086 } 087 return this.getNetworkService(name, request); 088 case JSON.NODE: 089 return this.getNode(request); 090 case JSON.PANEL: 091 case JSON.PANELS: 092 if (name == null) { 093 return this.getPanels(request.id); 094 } 095 return this.getPanel(request.locale, name, request.id); 096 case JSON.RAILROAD: 097 return this.getRailroad(request); 098 case JSON.SYSTEM_CONNECTION: 099 case JSON.SYSTEM_CONNECTIONS: 100 if (name == null) { 101 return this.getSystemConnections(request); 102 } 103 return this.getSystemConnection(name, request); 104 case JSON.CONFIG_PROFILE: 105 case JSON.CONFIG_PROFILES: 106 if (name == null) { 107 return this.getConfigProfiles(request); 108 } 109 return this.getConfigProfile(name, request); 110 case JSON.VERSION: 111 return this.getVersion(); 112 default: 113 throw new JsonException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 114 Bundle.getMessage(request.locale, JsonException.ERROR_UNKNOWN_TYPE, type), request.id); 115 } 116 } 117 118 @Override 119 public ArrayNode doGetList(String type, JsonNode data, JsonRequest request) throws JsonException { 120 switch (type) { 121 case JSON.METADATA: 122 return this.getMetadata(request); 123 case JSON.NETWORK_SERVICE: 124 case JSON.NETWORK_SERVICES: 125 return this.getNetworkServices(request); 126 case JSON.PANEL: 127 case JSON.PANELS: 128 return this.getPanels(request.id); 129 case JSON.SYSTEM_CONNECTION: 130 case JSON.SYSTEM_CONNECTIONS: 131 return this.getSystemConnections(request); 132 case JSON.CONFIG_PROFILE: 133 case JSON.CONFIG_PROFILES: 134 return this.getConfigProfiles(request); 135 default: 136 ArrayNode array = this.mapper.createArrayNode(); 137 JsonNode node = this.doGet(type, null, data, request); 138 if (node.isArray()) { 139 array.addAll((ArrayNode) node); 140 } else { 141 array.add(node); 142 } 143 return array; 144 } 145 } 146 147 @Override 148 // Use @CheckForNull to override non-null requirement of superclass 149 public JsonNode doPost(String type, @CheckForNull String name, 150 JsonNode data, JsonRequest request) throws JsonException { 151 log.debug("doPost(type='{}', name='{}', data='{}')", type, name, data); 152 // This will be expanded with more cases and warrants a CASE rather than an IF 153 switch (type) { 154 case JSON.RAILROAD: 155 InstanceManager.getDefault(WebServerPreferences.class).setRailroadName(name); 156 break; 157 default: 158 log.debug("Received unexpected POST command: '{}'", type); 159 break; 160 } 161 // Implicitly answer all doPost the way an equivalent doGet would be answered. 162 return this.doGet(type, name, data, request); 163 } 164 165 /** 166 * @return JSON map of complete versions and URL part for protocols 167 * @throws JsonException if a protocol version is not available 168 */ 169 public JsonNode getVersion() throws JsonException { 170 ObjectNode data = mapper.createObjectNode(); 171 for (String version : JSON.VERSIONS) { 172 try { 173 Field field; 174 field = JSON.class.getDeclaredField(version.toUpperCase() + "_PROTOCOL_VERSION"); 175 data.put(field.get(null).toString(), version); 176 } catch ( 177 IllegalAccessException | 178 IllegalArgumentException | 179 NoSuchFieldException | 180 SecurityException ex) { 181 throw new JsonException(500, ex, 0); 182 } 183 } 184 return message(JSON.VERSION, data, 0); 185 } 186 187 /** 188 * Send a JSON {@link jmri.server.json.JSON#HELLO} message. 189 * 190 * @param heartbeat seconds in which a client must send a message before its 191 * connection is broken 192 * @param request the JSON request 193 * @return the JSON hello message 194 */ 195 public JsonNode getHello(int heartbeat, @Nonnull JsonRequest request) { 196 ObjectNode data = mapper.createObjectNode(); 197 data.put(JSON.JMRI, jmri.Version.name()); 198 data.put(JSON.JSON, JSON.V5_PROTOCOL_VERSION); 199 data.put(JSON.VERSION, JSON.V5); 200 data.put(JSON.HEARTBEAT, Math.round(heartbeat * 0.9f)); 201 data.put(JSON.RAILROAD, InstanceManager.getDefault(WebServerPreferences.class).getRailroadName()); 202 data.put(JSON.NODE, NodeIdentity.networkIdentity()); 203 Profile activeProfile = ProfileManager.getDefault().getActiveProfile(); 204 data.put(JSON.ACTIVE_PROFILE, activeProfile != null ? activeProfile.getName() : null); 205 return message(JSON.HELLO, data, request.id); 206 } 207 208 /** 209 * Get a JSON message with a metadata element from {@link jmri.Metadata}. 210 * 211 * @param name The metadata element to get 212 * @param request the JSON request 213 * @return JSON metadata element 214 * @throws JsonException if name is not a recognized metadata element 215 */ 216 public JsonNode getMetadata(@Nonnull String name, @Nonnull JsonRequest request) throws JsonException { 217 String metadata = Metadata.getBySystemName(name); 218 ObjectNode data = mapper.createObjectNode(); 219 if (metadata != null) { 220 data.put(JSON.NAME, name); 221 data.put(JSON.VALUE, Metadata.getBySystemName(name)); 222 } else { 223 throw new JsonException(404, 224 Bundle.getMessage(request.locale, JsonException.ERROR_OBJECT, JSON.METADATA, name), 225 request.id); 226 } 227 return message(JSON.METADATA, data, request.id); 228 } 229 230 /** 231 * Get a JSON message with a metadata element from {@link jmri.Metadata}. 232 * 233 * @param locale The client's Locale. 234 * @param name The metadata element to get. 235 * @param id message id set by client 236 * @return JSON metadata element. 237 * @throws JsonException if name is not a recognized metadata element. 238 */ 239 public JsonNode getMetadata(Locale locale, String name, int id) throws JsonException { 240 return getMetadata(name, new JsonRequest(locale, JSON.V5, JSON.GET, id)); 241 } 242 243 /** 244 * Get a JSON array of metadata elements as listed by 245 * {@link jmri.Metadata#getSystemNameList()}. 246 * 247 * @param request the JSON request 248 * @return Array of JSON metadata elements 249 * @throws JsonException if thrown by 250 * {@link #getMetadata(java.util.Locale, java.lang.String, int)} 251 */ 252 public ArrayNode getMetadata(@Nonnull JsonRequest request) throws JsonException { 253 ArrayNode root = mapper.createArrayNode(); 254 for (String name : Metadata.getSystemNameList()) { 255 root.add(getMetadata(name, request)); 256 } 257 return root; 258 } 259 260 /** 261 * Get a running {@link jmri.util.zeroconf.ZeroConfService} using the 262 * protocol as the name of the service. 263 * 264 * @param name the service protocol 265 * @param request the JSON request 266 * @return the JSON networkService message 267 * @throws JsonException if type is not a running zeroconf networking 268 * protocol 269 */ 270 public JsonNode getNetworkService(@Nonnull String name, @Nonnull JsonRequest request) throws JsonException { 271 for (ZeroConfService service : InstanceManager.getDefault(ZeroConfServiceManager.class).allServices()) { 272 if (service.getType().equals(name)) { 273 return this.getNetworkService(service, request.id); 274 } 275 } 276 throw new JsonException(404, 277 Bundle.getMessage(request.locale, JsonException.ERROR_OBJECT, JSON.NETWORK_SERVICE, name), 278 request.id); 279 } 280 281 private JsonNode getNetworkService(ZeroConfService service, int id) { 282 ObjectNode data = mapper.createObjectNode(); 283 data.put(JSON.NAME, service.getType()); 284 data.put(JSON.USERNAME, service.getName()); 285 data.put(JSON.PORT, service.getServiceInfo().getPort()); 286 data.put(JSON.TYPE, service.getType()); 287 Enumeration<String> pe = service.getServiceInfo().getPropertyNames(); 288 while (pe.hasMoreElements()) { 289 String pn = pe.nextElement(); 290 data.put(pn, service.getServiceInfo().getPropertyString(pn)); 291 } 292 return message(JSON.NETWORK_SERVICE, data, id); 293 } 294 295 /** 296 * @param request the JSON request 297 * @return the JSON networkServices message. 298 */ 299 public ArrayNode getNetworkServices(@Nonnull JsonRequest request) { 300 ArrayNode root = mapper.createArrayNode(); 301 InstanceManager.getDefault(ZeroConfServiceManager.class).allServices().stream() 302 .forEach(service -> root.add(this.getNetworkService(service, request.id))); 303 return root; 304 } 305 306 /** 307 * @param locale the client's Locale. 308 * @param id message id set by client 309 * @return the JSON networkServices message. 310 */ 311 public ArrayNode getNetworkServices(Locale locale, int id) { 312 return getNetworkServices(new JsonRequest(locale, JSON.V5, JSON.GET, id)); 313 } 314 315 /** 316 * Send a JSON {@link jmri.server.json.JSON#NODE} message containing the 317 * JMRI node identity and former identities. 318 * 319 * @param request the JSON request 320 * @return the JSON node message 321 * @see jmri.util.node.NodeIdentity 322 */ 323 public JsonNode getNode(JsonRequest request) { 324 ObjectNode data = mapper.createObjectNode(); 325 data.put(JSON.NODE, NodeIdentity.networkIdentity()); 326 ArrayNode nodes = mapper.createArrayNode(); 327 NodeIdentity.formerIdentities().stream().forEach(nodes::add); 328 data.set(JSON.FORMER_NODES, nodes); 329 return message(JSON.NODE, data, request.id); 330 } 331 332 /** 333 * return a JSON {@link jmri.server.json.JSON#NODE} message containing the 334 * requested panel details 335 * 336 * @param locale the client's Locale 337 * @param name panel name to return 338 * @param id message id set by client 339 * @return the JSON panel message. 340 * @throws JsonException if panel not found 341 */ 342 public JsonNode getPanel(Locale locale, String name, int id) throws JsonException { 343 ArrayNode panels = getPanels(JSON.XML, id); 344 for (JsonNode panel : panels) { 345 if (panel.path(JSON.DATA).path(JSON.NAME).asText().equals(name)) { 346 return message(JSON.PANEL, panel.path(JSON.DATA), id); 347 } 348 } 349 throw new JsonException(404, Bundle.getMessage(locale, JsonException.ERROR_OBJECT, JSON.PANEL, name), id); 350 } 351 352 public ObjectNode getPanel(Editor editor, String format, int id) { 353 if (editor.getAllowInFrameServlet()) { 354 JFrame frame = editor.getTargetFrame(); 355 if (frame != null) { 356 String title = frame.getTitle(); 357 if (!title.isEmpty() && 358 !Arrays.asList(InstanceManager.getDefault(WebServerPreferences.class).getDisallowedFrames()) 359 .contains(title)) { 360 String type = PANEL_PANEL; 361 String name = "Panel"; 362 if (editor instanceof ControlPanelEditor) { 363 type = CONTROL_PANEL; 364 name = "ControlPanel"; 365 } else if (editor instanceof LayoutEditor) { 366 type = LAYOUT_PANEL; 367 name = "Layout"; 368 } else if (editor instanceof SwitchboardEditor) { 369 type = SWITCHBOARD_PANEL; 370 name = "Switchboard"; 371 } 372 ObjectNode data = this.mapper.createObjectNode(); 373 data.put(NAME, name + "/" + title.replace(" ", "%20").replace("#", "%23")); // NOI18N 374 data.put(URL, "/panel/" + data.path(NAME).asText() + "?format=" + format); // NOI18N 375 data.put(USERNAME, title); 376 data.put(TYPE, type); 377 return message(PANEL, data, id); 378 } 379 } 380 } 381 return null; 382 } 383 384 public ArrayNode getPanels(String format, int id) { 385 ArrayNode root = mapper.createArrayNode(); 386 // list loaded Panels (ControlPanelEditor, PanelEditor, LayoutEditor, 387 // SwitchboardEditor) 388 InstanceManager.getDefault(EditorManager.class).getAll().stream() 389 .map(editor -> this.getPanel(editor, format, id)) 390 .filter(Objects::nonNull).forEach(root::add); 391 return root; 392 } 393 394 public ArrayNode getPanels(int id) { 395 return this.getPanels(JSON.XML, id); 396 } 397 398 /** 399 * return a JSON {@link jmri.server.json.JSON#NODE} message containing the 400 * Railroad from the Railroad Name preferences. 401 * 402 * @param request the JSON request 403 * @return the JSON railroad name message 404 */ 405 public JsonNode getRailroad(@Nonnull JsonRequest request) { 406 ObjectNode data = mapper.createObjectNode(); 407 data.put(JSON.NAME, InstanceManager.getDefault(WebServerPreferences.class).getRailroadName()); 408 return message(JSON.RAILROAD, data, request.id); 409 } 410 411 /** 412 * return a JSON {@link jmri.server.json.JSON#NODE} message containing the 413 * requested systemConnection details 414 * 415 * @param name system connection name to return 416 * @param request the JSON request 417 * @return the JSON systemConnections message 418 * @throws JsonException if systemConnection not found 419 */ 420 public JsonNode getSystemConnection(String name, JsonRequest request) throws JsonException { 421 for (JsonNode connection : getSystemConnections(request)) { 422 JsonNode data = connection.path(JSON.DATA); 423 if (data.path(JSON.NAME).asText().equals(name)) { 424 return message(JSON.SYSTEM_CONNECTION, data, request.id); 425 } 426 } 427 throw new JsonException(HttpServletResponse.SC_NOT_FOUND, 428 Bundle.getMessage(request.locale, JsonException.ERROR_NOT_FOUND, JSON.SYSTEM_CONNECTION, name), 429 request.id); 430 } 431 432 /** 433 * return a JSON array containing the defined system connections 434 * 435 * @param request the JSON request 436 * @return the JSON systemConnections message. 437 */ 438 public ArrayNode getSystemConnections(@Nonnull JsonRequest request) { 439 ArrayNode root = mapper.createArrayNode(); 440 ArrayList<String> prefixes = new ArrayList<>(); 441 for (ConnectionConfig config : InstanceManager.getDefault(ConnectionConfigManager.class)) { 442 if (!config.getDisabled()) { 443 ObjectNode data = mapper.createObjectNode(); 444 data.put(JSON.NAME, config.getConnectionName()); 445 data.put(JSON.PREFIX, config.getAdapter().getSystemConnectionMemo().getSystemPrefix()); 446 data.put(JSON.MFG, config.getManufacturer()); 447 data.put(JSON.DESCRIPTION, 448 Bundle.getMessage(request.locale, "ConnectionSucceeded", config.getConnectionName(), 449 config.name(), config.getInfo())); 450 prefixes.add(config.getAdapter().getSystemConnectionMemo().getSystemPrefix()); 451 root.add(message(JSON.SYSTEM_CONNECTION, data, request.id)); 452 } 453 } 454 InstanceManager.getList(SystemConnectionMemo.class).stream().map(instance -> instance) 455 .filter(memo -> (!memo.getDisabled() && !prefixes.contains(memo.getSystemPrefix()))) 456 .forEach(memo -> { 457 ObjectNode data = mapper.createObjectNode(); 458 data.put(JSON.NAME, memo.getUserName()); 459 data.put(JSON.PREFIX, memo.getSystemPrefix()); 460 data.putNull(JSON.MFG); 461 data.putNull(JSON.DESCRIPTION); 462 prefixes.add(memo.getSystemPrefix()); 463 root.add(message(JSON.SYSTEM_CONNECTION, data, request.id)); 464 }); 465 // Following is required because despite there being a 466 // SystemConnectionMemo for the default internal connection, it is not 467 // used for the default internal connection. This allows a client to map 468 // the server's internal objects. 469 SystemConnectionMemo internal = InstanceManager.getDefault(InternalSystemConnectionMemo.class); 470 if (!prefixes.contains(internal.getSystemPrefix())) { 471 ObjectNode data = mapper.createObjectNode(); 472 data.put(JSON.NAME, internal.getUserName()); 473 data.put(JSON.PREFIX, internal.getSystemPrefix()); 474 data.putNull(JSON.MFG); 475 data.putNull(JSON.DESCRIPTION); 476 root.add(message(JSON.SYSTEM_CONNECTION, data, request.id)); 477 } 478 return root; 479 } 480 481 /** 482 * Get a JSON message containing the requested configuration profile. 483 * 484 * @param profile the requested profile 485 * @param manager the in use profile manager 486 * @param request the JSON request 487 * @return the data for this profile as a JSON Node 488 */ 489 private JsonNode getConfigProfile(@Nonnull Profile profile, @Nonnull ProfileManager manager, 490 @Nonnull JsonRequest request) { 491 boolean active = profile == manager.getActiveProfile(); 492 boolean next = profile == manager.getNextActiveProfile(); 493 boolean isAutoStart = (active && manager.isAutoStartActiveProfile()); 494 ObjectNode data = mapper.createObjectNode(); 495 data.put(JSON.USERNAME, profile.getName()); 496 data.put(JSON.UNIQUE_ID, profile.getUniqueId()); 497 data.put(JSON.NAME, profile.getId()); 498 data.put(JSON.IS_ACTIVE_PROFILE, active); 499 if (request.version.equals(JSON.V5)) { 500 // this is not a property of a profile 501 data.put(JSON.IS_AUTO_START, isAutoStart); 502 } 503 data.put(JSON.IS_NEXT_PROFILE, next); 504 return message(JSON.CONFIG_PROFILE, data, request.id); 505 } 506 507 /** 508 * Get the named configuration profile. 509 * 510 * @param name the Profile name 511 * @param request the JSON request 512 * @return the JSON configProfiles message 513 * @throws JsonException if the requested configProfile is not found 514 */ 515 public JsonNode getConfigProfile(@Nonnull String name, @Nonnull JsonRequest request) throws JsonException { 516 ProfileManager manager = ProfileManager.getDefault(); 517 for (Profile profile : manager.getProfiles()) { 518 if (profile.getId().equals(name)) { 519 return getConfigProfile(profile, manager, request); 520 } 521 } 522 throw new JsonException(HttpServletResponse.SC_NOT_FOUND, 523 Bundle.getMessage(request.locale, JsonException.ERROR_OBJECT, JSON.CONFIG_PROFILE, name), 524 request.id); 525 } 526 527 /** 528 * Get a JSON array of all configuration profiles. 529 * 530 * @param request the JSON request 531 * @return the JSON configProfiles message 532 */ 533 public ArrayNode getConfigProfiles(@Nonnull JsonRequest request) { 534 ArrayNode root = mapper.createArrayNode(); 535 ProfileManager manager = ProfileManager.getDefault(); 536 for (Profile profile : manager.getProfiles()) { 537 if (profile != null) { 538 root.add(getConfigProfile(profile, manager, request)); 539 } 540 } 541 return root; 542 } 543 544 /** 545 * Gets the {@link jmri.DccLocoAddress} for a String in the form 546 * {@code number(type)} or {@code number}. 547 * <p> 548 * Type may be {@code L} for long or {@code S} for short. If the type is not 549 * specified, type is assumed to be short. 550 * 551 * @param address the address 552 * @return The DccLocoAddress for address 553 */ 554 public static DccLocoAddress addressForString(String address) { 555 String[] components = address.split("[()]"); 556 int number = Integer.parseInt(components[0]); 557 boolean isLong = false; 558 if (components.length > 1 && "L".equalsIgnoreCase(components[1])) { 559 isLong = true; 560 } 561 return new DccLocoAddress(number, isLong); 562 } 563 564 @Override 565 public JsonNode doSchema(String type, boolean server, JsonRequest request) throws JsonException { 566 int id = request.id; 567 try { 568 switch (type) { 569 case JSON.CONFIG_PROFILE: 570 case JSON.CONFIG_PROFILES: 571 return doSchema(type, 572 server, 573 "jmri/server/json/util/configProfile-server.json", 574 "jmri/server/json/util/configProfile-client.json", 575 id); 576 case JSON.NETWORK_SERVICE: 577 case JSON.NETWORK_SERVICES: 578 return doSchema(type, 579 server, 580 "jmri/server/json/util/networkService-server.json", 581 "jmri/server/json/util/networkService-client.json", 582 id); 583 case JSON.PANEL: 584 case JSON.PANELS: 585 return doSchema(type, 586 server, 587 "jmri/server/json/util/panel-server.json", 588 "jmri/server/json/util/panel-client.json", 589 id); 590 case JSON.SYSTEM_CONNECTION: 591 case JSON.SYSTEM_CONNECTIONS: 592 return doSchema(type, 593 server, 594 "jmri/server/json/util/systemConnection-server.json", 595 "jmri/server/json/util/systemConnection-client.json", 596 id); 597 case JsonException.ERROR: 598 case JSON.LIST: 599 case JSON.PONG: 600 if (server) { 601 return doSchema(type, server, 602 this.mapper.readTree(this.getClass().getClassLoader() 603 .getResource(RESOURCE_PATH + type + "-server.json")), 604 id); 605 } else { 606 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 607 Bundle.getMessage(request.locale, "NotAClientType", type), id); 608 } 609 case JSON.LOCALE: 610 case JSON.PING: 611 if (!server) { 612 return doSchema(type, server, 613 this.mapper.readTree(this.getClass().getClassLoader() 614 .getResource(RESOURCE_PATH + type + "-client.json")), 615 id); 616 } else { 617 throw new JsonException(HttpServletResponse.SC_BAD_REQUEST, 618 Bundle.getMessage(request.locale, "NotAServerType", type), id); 619 } 620 case JSON.GOODBYE: 621 case JSON.HELLO: 622 case JSON.METADATA: 623 case JSON.NODE: 624 case JSON.RAILROAD: 625 case JSON.VERSION: 626 return doSchema(type, 627 server, 628 RESOURCE_PATH + type + "-server.json", 629 RESOURCE_PATH + type + "-client.json", 630 id); 631 default: 632 throw new JsonException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 633 Bundle.getMessage(request.locale, JsonException.ERROR_UNKNOWN_TYPE, type), id); 634 } 635 } catch (IOException ex) { 636 throw new JsonException(500, ex, id); 637 } 638 } 639}