001// License: GPL. For details, see LICENSE file. 002 003package org.openstreetmap.josm.io.remotecontrol.handler; 004 005import static org.openstreetmap.josm.tools.I18n.tr; 006 007import java.io.StringWriter; 008import java.util.Arrays; 009import java.util.stream.Stream; 010 011import javax.json.Json; 012import javax.json.JsonArrayBuilder; 013import javax.json.JsonObjectBuilder; 014 015import org.openstreetmap.josm.data.preferences.JosmUrls; 016import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; 017import org.openstreetmap.josm.io.remotecontrol.RemoteControl; 018import org.openstreetmap.josm.io.remotecontrol.RequestProcessor; 019import org.openstreetmap.josm.tools.Utils; 020 021/** 022 * Reports available commands as <a href="http://spec.openapis.org/oas/v3.0.3">OpenAPI</a>. 023 */ 024public class OpenApiHandler extends RequestHandler { 025 026 /** 027 * The remote control command name. 028 */ 029 public static final String command = "openapi.json"; 030 031 @Override 032 protected void handleRequest() { 033 JsonObjectBuilder openapi = getOpenApi(); 034 StringWriter stringWriter = new StringWriter(); 035 Json.createWriter(stringWriter).write(openapi.build()); 036 content = stringWriter.toString(); 037 contentType = "application/json"; 038 } 039 040 private JsonObjectBuilder getOpenApi() { 041 return Json.createObjectBuilder() 042 .add("openapi", "3.0.0") 043 .add("info", Json.createObjectBuilder() 044 .add("title", RequestProcessor.JOSM_REMOTE_CONTROL) 045 .add("version", RemoteControl.getVersion()) 046 .add("contact", Json.createObjectBuilder() 047 .add("name", "JOSM") 048 .add("url", JosmUrls.getInstance().getJOSMWebsite()))) 049 .add("servers", Json.createArrayBuilder() 050 .add(Json.createObjectBuilder().add("url", "http://localhost:8111/"))) 051 .add("paths", getHandlers()); 052 } 053 054 private JsonObjectBuilder getHandlers() { 055 JsonObjectBuilder paths = Json.createObjectBuilder(); 056 RequestProcessor.getHandlersInfo(null) 057 .forEach(handler -> paths.add("/" + handler.getCommand(), getHandler(handler))); 058 return paths; 059 } 060 061 private JsonObjectBuilder getHandler(RequestHandler handler) { 062 JsonArrayBuilder parameters = Json.createArrayBuilder(); 063 Stream.concat( 064 Arrays.stream(handler.getMandatoryParams()), 065 Arrays.stream(handler.getOptionalParams()) 066 ).distinct().map(param -> Json.createObjectBuilder() 067 .add("name", param) 068 .add("in", "query") 069 .add("required", Arrays.asList(handler.getMandatoryParams()).contains(param)) 070 .add("schema", Json.createObjectBuilder().add("type", "string")) // TODO fix type 071 ).forEach(parameters::add); 072 return Json.createObjectBuilder().add("get", Json.createObjectBuilder() 073 .add("description", getDescription(handler)) 074 .add("operationId", handler.getCommand()) 075 .add("parameters", parameters) 076 .add("responses", Json.createObjectBuilder() 077 .add("200", Json.createObjectBuilder().add("description", "successful operation"))) 078 ); 079 } 080 081 private String getDescription(RequestHandler handler) { 082 return Utils.firstNonNull(handler.getUsage(), "") 083 + "\n\n* " + String.join("\n* ", handler.getUsageExamples()); 084 } 085 086 @Override 087 public String getUsage() { 088 return "JOSM RemoteControl as OpenAPI Specification"; 089 } 090 091 @Override 092 public String[] getUsageExamples() { 093 return new String[]{"https://petstore.swagger.io/?url=http://localhost:8111/openapi.json", "https://swagger.io/specification/"}; 094 } 095 096 @Override 097 public String getPermissionMessage() { 098 return tr("Remote Control has been asked to report its supported features. This enables web sites to guess a running JOSM version"); 099 } 100 101 @Override 102 public PermissionPrefWithDefault getPermissionPref() { 103 return PermissionPrefWithDefault.READ_PROTOCOL_VERSION; 104 } 105 106 @Override 107 public String[] getMandatoryParams() { 108 return new String[0]; 109 } 110 111 @Override 112 protected void validateRequest() { 113 // Nothing to do 114 } 115}