Ticket #19336: 19336-poc.patch

File 19336-poc.patch, 12.2 KB (added by simon04, 3 years ago)
  • new file resources/data/GetCapabilities.xml

    commit 013e837825607bb8bde748d83df4bbe028ae0c64
    Author: Simon Legner <Simon.Legner@gmail.com>
    Date:   2021-03-20 08:44:43 +0100
    
        WIP #19336 - Implement WMS server
    
    diff --git a/resources/data/GetCapabilities.xml b/resources/data/GetCapabilities.xml
    new file mode 100644
    index 000000000..bc7a9ccab
    - +  
     1<?xml version="1.0" encoding="UTF-8"?>
     2<WMS_Capabilities
     3        version="1.3.0"
     4        xmlns="http://www.opengis.net/wms"
     5        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     6        xmlns:xlink="http://www.w3.org/1999/xlink"
     7        xsi:schemaLocation="http://www.opengis.net/wms http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd">
     8    <Service>
     9        <Name>WMS</Name>
     10        <Title>JOSM</Title>
     11        <Abstract>...</Abstract>
     12        <OnlineResource xlink:href="http://localhost:8111/wms?"/>
     13        <Fees>none</Fees>
     14        <AccessConstraints>ODbL</AccessConstraints>
     15    </Service>
     16    <Capability>
     17        <Request>
     18            <GetCapabilities>
     19                <Format>application/vnd.ogc.wms_xml</Format>
     20                <Format>text/xml</Format>
     21                <DCPType>
     22                    <HTTP>
     23                        <Get>
     24                            <OnlineResource xlink:href="http://localhost:8111/wms?"/>
     25                        </Get>
     26                    </HTTP>
     27                </DCPType>
     28            </GetCapabilities>
     29            <GetMap>
     30                <Format>image/png</Format>
     31                <DCPType>
     32                    <HTTP>
     33                        <Get>
     34                            <OnlineResource xlink:href="http://localhost:8111/wms?"/>
     35                        </Get>
     36                    </HTTP>
     37                </DCPType>
     38            </GetMap>
     39        </Request>
     40        <Exception>
     41            <Format>application/vnd.ogc.se_xml</Format>
     42            <Format>application/vnd.ogc.se_inimage</Format>
     43            <Format>application/vnd.ogc.se_blank</Format>
     44            <Format>text/xml</Format>
     45            <Format>XML</Format>
     46        </Exception>
     47        <Layer>
     48            <Title>JOSM Root</Title>
     49            <CRS>EPSG:3857</CRS>
     50            <Layer>
     51                <Title>JOSM Layer</Title>
     52                <Style>
     53                    <Name>JOSM Style</Name>
     54                    <Title>JOSM Style</Title>
     55                </Style>
     56            </Layer>
     57        </Layer>
     58    </Capability>
     59</WMS_Capabilities>
  • src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java

    diff --git a/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java b/src/org/openstreetmap/josm/io/remotecontrol/RequestProcessor.java
    index e03bfb4ce..c45d06b4d 100644
    a b import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHan  
    4444import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerForbiddenException;
    4545import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerOsmApiException;
    4646import org.openstreetmap.josm.io.remotecontrol.handler.VersionHandler;
     47import org.openstreetmap.josm.io.remotecontrol.handler.WmsHandler;
    4748import org.openstreetmap.josm.tools.Logging;
    4849import org.openstreetmap.josm.tools.Utils;
    4950
    public class RequestProcessor extends Thread {  
    171172            addRequestHandlerClass(VersionHandler.command, VersionHandler.class, true);
    172173            addRequestHandlerClass(FeaturesHandler.command, FeaturesHandler.class, true);
    173174            addRequestHandlerClass(OpenApiHandler.command, OpenApiHandler.class, true);
     175            addRequestHandlerClass(WmsHandler.command, WmsHandler.class, true);
    174176        }
    175177    }
    176178
    public class RequestProcessor extends Thread {  
    181183    public void run() {
    182184        Writer out = null; // NOPMD
    183185        try { // NOPMD
    184             out = new OutputStreamWriter(new BufferedOutputStream(request.getOutputStream()), RESPONSE_CHARSET);
     186            BufferedOutputStream raw = new BufferedOutputStream(request.getOutputStream());
     187            out = new OutputStreamWriter(raw, RESPONSE_CHARSET);
    185188            BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.US_ASCII)); // NOPMD
    186189
    187190            String get = in.readLine();
    public class RequestProcessor extends Thread {  
    262265                    handler.setUrl(url);
    263266                    handler.setSender(sender);
    264267                    handler.handle();
    265                     sendHeader(out, "200 OK", handler.getContentType(), false);
    266                     out.write("Content-length: " + handler.getContent().length()
    267                             + "\r\n");
    268                     out.write("\r\n");
    269                     out.write(handler.getContent());
    270                     out.flush();
     268                    if (handler instanceof WmsHandler) {
     269                        sendHeader(out, "200 OK", handler.getContentType(), null, -1);
     270                        out.flush();
     271                        ((WmsHandler) handler).handleRequest(raw);
     272                        raw.flush();
     273                    } else {
     274                        sendHeader(out, "200 OK", handler.getContentType(), RESPONSE_CHARSET, handler.getContent().length());
     275                        out.write(handler.getContent());
     276                        out.flush();
     277                    }
    271278                } catch (RequestHandlerOsmApiException ex) {
    272279                    Logging.debug(ex);
    273280                    sendBadGateway(out, ex.getMessage());
    public class RequestProcessor extends Thread {  
    305312    }
    306313
    307314    private static void sendErrorHtml(Writer out, int errorCode, String errorName, String helpHtml) throws IOException {
    308         sendHeader(out, errorCode + " " + errorName, "text/html", true);
     315        sendHeader(out, errorCode + " " + errorName, "text/html", RESPONSE_CHARSET, -1);
    309316        out.write(String.format(
    310317                RESPONSE_TEMPLATE,
    311318                "<title>" + errorName + "</title>",
    public class RequestProcessor extends Thread {  
    389396     *            The status string ("200 OK", "500", etc)
    390397     * @param contentType
    391398     *            The content type of the data sent
    392      * @param endHeaders
    393      *            If true, adds a new line, ending the headers.
     399     * @param charset The content charset
     400     * @param length The content length
     401     *
    394402     * @throws IOException
    395403     *             When error
    396404     */
    397     private static void sendHeader(Writer out, String status, String contentType,
    398             boolean endHeaders) throws IOException {
    399         out.write("HTTP/1.1 " + status + "\r\n");
    400         out.write("Date: " + new Date() + "\r\n");
    401         out.write("Server: " + JOSM_REMOTE_CONTROL + "\r\n");
    402         out.write("Content-type: " + contentType + "; charset=" + RESPONSE_CHARSET.name().toLowerCase(Locale.ENGLISH) + "\r\n");
    403         out.write("Access-Control-Allow-Origin: *\r\n");
    404         if (endHeaders)
    405             out.write("\r\n");
     405    private static void sendHeader(Appendable out, String status, String contentType, Charset charset, long length) throws IOException {
     406        out.append("HTTP/1.1 ").append(status).append("\r\n");
     407        out.append("Date: ").append(String.valueOf(new Date())).append("\r\n");
     408        out.append("Server: " + JOSM_REMOTE_CONTROL + "\r\n");
     409
     410        out.append("Content-type: ").append(contentType);
     411        if (charset != null) {
     412            out.append("; charset=").append(charset.name().toLowerCase(Locale.ENGLISH));
     413        }
     414        out.append("\r\n");
     415
     416        if (length > 0) {
     417            out.append("Content-length: ").append(String.valueOf(length)).append("\r\n");
     418        }
     419
     420        out.append("Access-Control-Allow-Origin: *\r\n");
     421
     422        // end header
     423        out.append("\r\n");
    406424    }
    407425
    408426    /**
  • new file src/org/openstreetmap/josm/io/remotecontrol/handler/WmsHandler.java

    diff --git a/src/org/openstreetmap/josm/io/remotecontrol/handler/WmsHandler.java b/src/org/openstreetmap/josm/io/remotecontrol/handler/WmsHandler.java
    new file mode 100644
    index 000000000..a504778e0
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.io.remotecontrol.handler;
     3
     4import org.openstreetmap.josm.gui.MainApplication;
     5import org.openstreetmap.josm.gui.mappaint.RenderingHelper;
     6import org.openstreetmap.josm.gui.mappaint.RenderingHelper.StyleData;
     7import org.openstreetmap.josm.io.CachedFile;
     8import org.openstreetmap.josm.io.IllegalDataException;
     9import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault;
     10import org.openstreetmap.josm.tools.CheckParameterUtil;
     11
     12import javax.imageio.ImageIO;
     13import java.awt.image.BufferedImage;
     14import java.io.IOException;
     15import java.io.OutputStream;
     16import java.net.URISyntaxException;
     17import java.util.Collections;
     18import java.util.Locale;
     19import java.util.Map;
     20import java.util.stream.Collectors;
     21
     22public class WmsHandler extends RequestHandler {
     23
     24    /**
     25     * The remote control command name.
     26     */
     27    public static final String command = "wms";
     28
     29    @Override
     30    protected void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException {
     31        if (args.get("request").equalsIgnoreCase("GetCapabilities")) {
     32            contentType = "text/xml";
     33        } else if (args.get("request").equalsIgnoreCase("GetMap")) {
     34            contentType = args.getOrDefault("format", "image/png");
     35        }
     36    }
     37
     38    public void handleRequest(OutputStream out) throws IOException {
     39        if (args.get("request").equalsIgnoreCase("GetCapabilities")) {
     40            byte[] bytes = new CachedFile("resource://data/GetCapabilities.xml").getByteContent();
     41            out.write(bytes);
     42        } else if (args.get("request").equalsIgnoreCase("GetMap")) {
     43            getMap(out);
     44        }
     45    }
     46
     47    private void getMap(OutputStream out) throws IOException {
     48//        double[] bbox = Pattern.compile(",").splitAsStream(args.get("bbox")).mapToDouble(Double::parseDouble).toArray();
     49//        ProjectionBounds projectionBounds = new ProjectionBounds();
     50//        projectionBounds.extend(new EastNorth(bbox[0], bbox[1]));
     51//        projectionBounds.extend(new EastNorth(bbox[2], bbox[3]));
     52//        System.out.println(projectionBounds);
     53//        Bounds bounds = ProjectionRegistry.getProjection().getLatLonBoundsBox(projectionBounds);
     54//        System.out.println(bounds);
     55        StyleData styleData = new StyleData();
     56        styleData.styleUrl = "resource://styles/standard/elemstyles.mapcss";
     57
     58        RenderingHelper renderingHelper = new RenderingHelper(
     59                MainApplication.getLayerManager().getActiveDataSet(),
     60                MainApplication.getMap().mapView.getRealBounds(),
     61                MainApplication.getMap().mapView.getScale(),
     62                Collections.singleton(styleData));
     63        try {
     64            BufferedImage image = renderingHelper.render();
     65            ImageIO.write(image, "png", out);
     66        } catch (IllegalDataException e) {
     67            throw new RuntimeException(e);
     68        }
     69    }
     70
     71    @Override
     72    protected void parseArgs() throws URISyntaxException {
     73        super.parseArgs();
     74        this.args = this.args.entrySet().stream().collect(Collectors.toMap(s -> s.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue));
     75        this.args.computeIfAbsent("service", k -> "WMS");
     76        this.args.computeIfAbsent("request", k -> "GetCapabilities");
     77    }
     78
     79    @Override
     80    public String[] getMandatoryParams() {
     81        return new String[]{};
     82    }
     83
     84    @Override
     85    public String[] getOptionalParams() {
     86        return new String[]{"service", "request", "version", "bbox", "layer"};
     87    }
     88
     89    @Override
     90    protected void validateRequest() throws RequestHandlerBadRequestException {
     91        CheckParameterUtil.ensureThat("WMS".equalsIgnoreCase(args.get("service")), "service=WMS");
     92        CheckParameterUtil.ensureParameterNotNull("WMS".equalsIgnoreCase(args.get("request")), "request");
     93    }
     94
     95    @Override
     96    public String getPermissionMessage() {
     97        return null;
     98    }
     99
     100    @Override
     101    public PermissionPrefWithDefault getPermissionPref() {
     102        return null;
     103    }
     104}