All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mapfish.print.map.readers.WMSMapReader Maven / Gradle / Ivy

/*
 * Copyright (C) 2013  Camptocamp
 *
 * This file is part of MapFish Print
 *
 * MapFish Print is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MapFish Print is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MapFish Print.  If not, see .
 */

package org.mapfish.print.map.readers;

import org.apache.log4j.Logger;
import org.json.JSONException;
import org.mapfish.print.RenderingContext;
import org.mapfish.print.Transformer;
import org.mapfish.print.map.ParallelMapTileLoader;
import org.mapfish.print.map.renderers.TileRenderer;
import org.mapfish.print.utils.PJsonArray;
import org.mapfish.print.utils.PJsonObject;
import org.pvalsecc.misc.StringUtils;
import org.pvalsecc.misc.URIUtils;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Support for the WMS protocol with possibilities to go through a WMS-C service
 * (TileCache).
 */
public class WMSMapReader extends TileableMapReader {

    private boolean strictEpsg4326;

    enum WMSVersion {
        VERSION1_1_1("1.1.1"), VERSION1_3_0("1.3.0");
        public final String code;

        WMSVersion(String code) {
            this.code = code;
        }

        public static WMSVersion find(String version) {
            for (WMSVersion wmsVersion : values()) {
                if (wmsVersion.code.equals(version)) {
                    return wmsVersion;
                }
            }

            throw new IllegalArgumentException("WMS Version: "+version+" is not a supported version");
        }

    }

    private static final WMSVersion DEFAULT_VERSION = WMSVersion.VERSION1_1_1;

    public static class Factory implements MapReaderFactory {
        @Override
        public List create(String type, RenderingContext context, PJsonObject params) {
            ArrayList target = new ArrayList();
            PJsonArray layers = params.getJSONArray("layers");
            PJsonArray styles = params.optJSONArray("styles");
            for (int i = 0; i < layers.size(); i++) {
                String layer = layers.getString(i);
                String style = "";
                if (styles != null && i < styles.size()) {
                    style = styles.getString(i);
                }
                target.add(new WMSMapReader(layer, style, context, params));
            }

            return target;
        }
    }

    public static final Logger LOGGER = Logger.getLogger(WMSMapReader.class);
    private final String format;
    protected final List layers = new ArrayList();
    private WMSVersion version;
    private final List styles = new ArrayList();

    private WMSMapReader(String layer, String style, RenderingContext context, PJsonObject params) {
        super(context, params);
        layers.add(layer);
        if (!context.getConfig().isIgnoreCapabilities()) {
            tileCacheLayerInfo = WMSServiceInfo.getInfo(baseUrl, context).getTileCacheLayer(layer);
        }
        styles.add(style);
        format = params.getString("format");
        version = WMSVersion.find(params.optString("version", DEFAULT_VERSION.code));
        final PJsonObject customParams = params.optJSONObject("customParams");

        if (customParams != null) {
            version = WMSVersion.find(customParams.optString("version", version.code));
        }

        if (version == WMSVersion.VERSION1_3_0 &&
            params.optString("srs", context.getGlobalParams().optString("srs", "CRS:4326")).equals("EPSG:4326")) {
            strictEpsg4326 = true;
        }
    }
    
    @Override
    protected String getMergeableValue(PJsonObject customParams,
            final List toBeSkipped, String key) throws JSONException {
        // adds support for an array of values for mergeable parameters
        // so that a single value can be specified for each single layer
        if(customParams.optJSONArray(key) != null) {
            String value = null;
            PJsonArray listOfValues = customParams.getJSONArray(key);
            int notUsed = -1;
            for(int count = 0; count< listOfValues.size() && notUsed == -1; count++) {
                value = listOfValues.getInternalArray().optString(count, null);
                if(value != null) {
                    notUsed = count;
                    listOfValues.getInternalArray().put(count, (String)null);
                }
            }
            if(notUsed == (listOfValues.size() - 1)) {
                toBeSkipped.add(key);
            }
            return value;
        } else {
            return super.getMergeableValue(customParams, toBeSkipped, key);
        }
    }
    
    @Override
    protected TileRenderer.Format getFormat() {
        if (format.equals("image/svg+xml")) {
            return TileRenderer.Format.SVG;
        } else if (format.equals("application/pdf") || format.equals("application/x-pdf")) {
            return TileRenderer.Format.PDF;
        } else {
            return TileRenderer.Format.BITMAP;
        }
    }
    @Override
    public void render(Transformer transformer, ParallelMapTileLoader parallelMapTileLoader, String srs, boolean first) {
        PJsonObject customParams = params.optJSONObject("customParams");

        // store the rotation to not change for other layers
        double oldAngle = transformer.getRotation();

        // native WMS rotation - only works in singleTile mode
        if (customParams != null && customParams.optString("angle") != null) { // For GeoServer
            transformer.setRotation(0);
        }
        if (params.optBool("useNativeAngle", false)) {
            String angle = String.valueOf(-Math.toDegrees(transformer.getRotation()));
            try {
                if (customParams != null) {
                    customParams.getInternalObj().put("angle", angle); // For GeoServer
                    customParams.getInternalObj().put("map_angle", angle); // For MapServer
                } else {
                    Map customMap = new HashMap();
                    customMap.put("angle", angle); // For GeoServer
                    customMap.put("map_angle", angle); // For MapServer
                    params.getInternalObj().put("customParams", customMap);
                }
                transformer.setRotation(0);
            } catch (org.json.JSONException e) {
                LOGGER.error("Unable to set angle: " + e.getClass().getName() + " - " + e.getMessage());
            }
        }
        super.render(transformer, parallelMapTileLoader, srs, first);
        // restore the rotation for other layers
        transformer.setRotation(oldAngle);
    }
    @Override
    protected void addCommonQueryParams(Map> result, Transformer transformer, String srs, boolean first) {
        URIUtils.setParamDefault(result, "FORMAT", format);
        URIUtils.setParamDefault(result, "LAYERS", StringUtils.join(layers, ","));
        URIUtils.setParamDefault(result, "SERVICE", "WMS");
        URIUtils.setParamDefault(result, "REQUEST", "GetMap");

        final String versionParamName = "VERSION";

        switch (version) {
            case VERSION1_3_0:
                URIUtils.setParamDefault(result, "CRS", srs);
                URIUtils.setParamDefault(result, versionParamName, version.code);
                break;
            default:
                URIUtils.setParamDefault(result, "SRS", srs);
                URIUtils.setParamDefault(result, versionParamName, WMSVersion.VERSION1_1_1.code);
        }

        if (!first) {
            URIUtils.setParamDefault(result, "TRANSPARENT", "true");
        }
        URIUtils.setParamDefault(result, "STYLES", StringUtils.join(styles, ","));
        URIUtils.setParamDefault(result, "format_options", "dpi:" + transformer.getDpi()); // For GeoServer
        URIUtils.setParamDefault(result, "map_resolution", String.valueOf(transformer.getDpi())); // For MapServer
        URIUtils.setParamDefault(result, "DPI", String.valueOf(transformer.getDpi())); // For QGIS mapserver

    }
    @Override
    public boolean testMerge(MapReader other) {
        if (canMerge(other)) {
            WMSMapReader wms = (WMSMapReader) other;
            layers.addAll(wms.layers);
            styles.addAll(wms.styles);
            return super.testMerge(other);
        } else {
            return false;
        }
    }
    @Override
    public boolean canMerge(MapReader other) {
        if (!super.canMerge(other)) {
            return false;
        }

        if (tileCacheLayerInfo != null && !context.getConfig().isTilecacheMerging()) {
            //no layer merge when tile cache is here and we are not configured to support it...
            return false;
        }

        if (other instanceof WMSMapReader) {
            WMSMapReader wms = (WMSMapReader) other;
            if (!format.equals(wms.format)) {
                return false;
            }

            if (tileCacheLayerInfo != null && wms.tileCacheLayerInfo != null) {
                if (!tileCacheLayerInfo.equals(wms.tileCacheLayerInfo)) {
                    //not the same tile cache config
                    return false;
                }
            } else if ((tileCacheLayerInfo == null) != (wms.tileCacheLayerInfo == null)) {
                //one layer has a tile cache config and not the other?!?!? Weird...
                LOGGER.warn("Between [" + this + "] and [" + wms + "], one has a tile cache config and not the other");
                return false;
            }
        } else {
            return false;
        }

        return true;
    }

    @Override
    protected URI getTileUri(URI commonUri, Transformer transformer, double minGeoX, double minGeoY, double maxGeoX, double maxGeoY,
                             long w, long h) throws URISyntaxException, UnsupportedEncodingException {

        Map> tileParams = new HashMap>();
        if (format.equals("image/svg+xml")) {
            double maxW = context.getConfig().getMaxSvgW(); // config setting in YAML called maxSvgWidth
            double maxH = context.getConfig().getMaxSvgH(); // config setting in YAML called maxSvgHeight
            double divisor;
            double width = transformer.getRotatedSvgW(); // width of the vector map
            double height = transformer.getRotatedSvgH(); // height of the vector map

            if (maxW < width || maxH < height) {
                /**
                 *  need to use maxW as divisor, smaller quotient for width means
                 *  more constraining factor is max width
                 */
                if (maxW / maxH < width / height) {
                    //LOGGER.warn("before width="+width+" height="+height);
                    divisor = width / maxW;
                    width = maxW;
                    height = height / divisor;
                    //LOGGER.warn("after width="+width+" height="+height);
                } else {
                    //LOGGER.warn("before width="+width+" height="+height);
                    divisor = height / maxH;
                    height = maxH;
                    width = width / divisor;
                    //LOGGER.warn("after width="+width+" height="+height);
                }
            }
            URIUtils.addParamOverride(tileParams, "WIDTH", Long.toString(Math.round(width)));
            URIUtils.addParamOverride(tileParams, "HEIGHT", Long.toString(Math.round(height)));
        } else {
            URIUtils.addParamOverride(tileParams, "WIDTH", Long.toString(w));
            URIUtils.addParamOverride(tileParams, "HEIGHT", Long.toString(h));
        }

        final String bbox;

        switch (version) {
            case VERSION1_3_0:
                if (strictEpsg4326) {
                    bbox = String.format("%s,%s,%s,%s", minGeoY, minGeoX, maxGeoY, maxGeoX);
                } else {
                    bbox = String.format("%s,%s,%s,%s", minGeoX, minGeoY, maxGeoX, maxGeoY);
                }
                break;
            default:
                bbox = String.format("%s,%s,%s,%s", minGeoX, minGeoY, maxGeoX, maxGeoY);
        }

        URIUtils.addParamOverride(tileParams, "BBOX", bbox);
        return URIUtils.addParams(commonUri, tileParams, OVERRIDE_ALL);
    }
    @Override
    public String toString() {
        return StringUtils.join(layers, ", ");
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy