Package org.mapfish.print.map.geotools

Source Code of org.mapfish.print.map.geotools.FeaturesParser

/*
* Copyright (C) 2014  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 <http://www.gnu.org/licenses/>.
*/

package org.mapfish.print.map.geotools;

import com.google.common.collect.Sets;
import com.google.common.io.CharSource;
import com.google.common.io.CharStreams;
import com.google.common.io.Closer;
import com.google.common.io.Files;
import com.vividsolutions.jts.geom.Geometry;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultEngineeringCRS;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mapfish.print.Constants;
import org.mapfish.print.ExceptionUtils;
import org.mapfish.print.FileUtils;
import org.mapfish.print.PrintException;
import org.mapfish.print.config.Template;
import org.mapfish.print.http.MfClientHttpRequestFactory;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpResponse;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Iterator;
import java.util.Set;
import javax.annotation.Nonnull;

/**
* Parser for GeoJson features collection.
* <p/>
* Created by Stéphane Brunner on 16/4/14.
*/
public class FeaturesParser {
    private static final Logger LOGGER = LoggerFactory.getLogger(FeaturesParser.class);
    private final MfClientHttpRequestFactory httpRequestFactory;
    private final boolean forceLongitudeFirst;

    /**
     * Construct.
     *
     * @param httpRequestFactory  the HTTP request factory
     * @param forceLongitudeFirst if true then force longitude coordinate as first coordinate
     */
    public FeaturesParser(final MfClientHttpRequestFactory httpRequestFactory, final boolean forceLongitudeFirst) {
        this.httpRequestFactory = httpRequestFactory;
        this.forceLongitudeFirst = forceLongitudeFirst;
    }

    /**
     * Get the features collection from a GeoJson inline string or URL.
     *
     * @param template the template
     * @param features what to parse
     * @return the feature collection
     * @throws IOException
     */
    public final SimpleFeatureCollection autoTreat(final Template template, final String features) throws IOException {
        SimpleFeatureCollection featuresCollection = treatStringAsURL(template, features);
        if (featuresCollection == null) {
            featuresCollection = treatStringAsGeoJson(features);
        }
        return featuresCollection;
    }

    /**
     * Get the features collection from a GeoJson URL.
     *
     * @param template   the template
     * @param geoJsonUrl what to parse
     * @return the feature collection
     */
    public final SimpleFeatureCollection treatStringAsURL(final Template template, final String geoJsonUrl) throws IOException {
        URL url;
        try {
            url = FileUtils.testForLegalFileUrl(template.getConfiguration(), new URL(geoJsonUrl));
        } catch (MalformedURLException e) {
            return null;
        }

        final String geojsonString;
        Closer closer = Closer.create();
        try {
            Reader input;
            if (url.getProtocol().equalsIgnoreCase("file")) {
                final CharSource charSource = Files.asCharSource(new File(url.getFile()), Constants.DEFAULT_CHARSET);
                input = closer.register(charSource.openBufferedStream());
            } else {
                final ClientHttpResponse response = closer.register(this.httpRequestFactory.createRequest(url.toURI(),
                        HttpMethod.GET).execute());

                input = closer.register(new BufferedReader(new InputStreamReader(response.getBody(), Constants.DEFAULT_CHARSET)));
            }
            geojsonString = CharStreams.toString(input);
        } catch (URISyntaxException e) {
            throw ExceptionUtils.getRuntimeException(e);
        } finally {
            closer.close();
        }

        return treatStringAsGeoJson(geojsonString);
    }

    /**
     * Get the features collection from a GeoJson inline string.
     *
     * @param geoJsonString what to parse
     * @return the feature collection
     * @throws IOException
     */
    public final SimpleFeatureCollection treatStringAsGeoJson(final String geoJsonString) throws IOException {
        return readFeatureCollection(geoJsonString);
    }

    private SimpleFeatureCollection readFeatureCollection(final String geojsonData) throws IOException {
        String convertedGeojsonObject = convertToGeoJsonCollection(geojsonData);

        FeatureJSON geoJsonReader = new FeatureJSON();
        final SimpleFeatureType featureType = createFeatureType(convertedGeojsonObject);
        if (featureType != null) {
            geoJsonReader.setFeatureType(featureType);
        }
        ByteArrayInputStream input = new ByteArrayInputStream(convertedGeojsonObject.getBytes(Constants.DEFAULT_CHARSET));

        return (SimpleFeatureCollection) geoJsonReader.readFeatureCollection(input);
    }

    private String convertToGeoJsonCollection(final String geojsonData) {
        String convertedGeojsonObject = geojsonData.trim();
        if (convertedGeojsonObject.startsWith("[")) {
            convertedGeojsonObject = "{\"type\": \"FeatureCollection\", \"features\": " + convertedGeojsonObject + "}";
        }
        return convertedGeojsonObject;
    }

    private SimpleFeatureType createFeatureType(@Nonnull final String geojsonData) {
        try {
            JSONObject geojson = new JSONObject(geojsonData);
            if (geojson.has("type") && geojson.getString("type").equalsIgnoreCase("FeatureCollection")) {
                CoordinateReferenceSystem crs = parseCoordinateReferenceSystem(geojson);
                SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
                builder.setName("GeosjonFeatureType");
                final JSONArray features = geojson.getJSONArray("features");

                Set<String> allAttributes = Sets.newHashSet();
                Class<Geometry> geomType = null;
                for (int i = 0; i < features.length(); i++) {
                    final JSONObject feature = features.getJSONObject(i);
                    final JSONObject properties = feature.getJSONObject("properties");
                    final Iterator keys = properties.keys();
                    while (keys.hasNext()) {
                        String nextKey = (String) keys.next();
                        if (!allAttributes.contains(nextKey)) {
                            allAttributes.add(nextKey);
                            builder.add(nextKey, Object.class);
                        }
                        if (geomType != Geometry.class) {
                            Class<Geometry> thisGeomType = parseGeometryType(feature);
                            if (thisGeomType != null) {
                                if (geomType == null) {
                                    geomType = thisGeomType;
                                } else if (geomType != thisGeomType) {
                                    geomType = Geometry.class;
                                }
                            }
                        }
                    }
                }

                builder.add("geometry", geomType, crs);
                builder.setDefaultGeometry("geometry");
                return builder.buildFeatureType();
            } else {
                return null;
            }
        } catch (JSONException e) {
            throw new PrintException("Invalid geoJSON: \n" + geojsonData + ": " + e.getMessage(), e);
        }

    }

    @SuppressWarnings("unchecked")
    private Class<Geometry> parseGeometryType(@Nonnull final JSONObject featureJson) throws JSONException {
        JSONObject geomJson = featureJson.optJSONObject("geometry");
        if (geomJson == null) {
            return null;
        }
        String geomTypeString = geomJson.optString("type", "Geometry");
        if (geomTypeString.equalsIgnoreCase("Positions")) {
            return Geometry.class;
        } else {
            try {
                return (Class<Geometry>) Class.forName("com.vividsolutions.jts.geom." + geomTypeString);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("Unrecognized geometry type in geojson: " + geomTypeString);
            }
        }
    }

    private CoordinateReferenceSystem parseCoordinateReferenceSystem(final JSONObject geojson) {
        CoordinateReferenceSystem crs = DefaultEngineeringCRS.GENERIC_2D;
        StringBuilder code = new StringBuilder();
        try {
            if (geojson.has("crs")) {
                JSONObject crsJson = geojson.getJSONObject("crs");
                if (crsJson.has("type")) {
                    code.append(crsJson.getString("type"));
                }

                if (crsJson.has("properties")) {
                    final JSONObject propertiesJson = crsJson.getJSONObject("properties");
                    if (propertiesJson.has("code")) {
                        if (code.length() > 0) {
                            code.append(":");
                        }
                        code.append(propertiesJson.getString("code"));
                    }
                }
            }
        } catch (JSONException e) {
            LOGGER.warn("Error reading the required elements to parse crs of the geojson: \n" + geojson, e);
        }
        try {
            if (code.length() > 0) {
                crs = CRS.decode(code.toString(), this.forceLongitudeFirst);
            }
        } catch (NoSuchAuthorityCodeException e) {
            LOGGER.warn("No CRS with code: " + code + ".\nRead from geojson: \n" + geojson);
        } catch (FactoryException e) {
            LOGGER.warn("Error loading CRS with code: " + code + ".\nRead from geojson: \n" + geojson);
        }
        return crs;
    }
}
TOP

Related Classes of org.mapfish.print.map.geotools.FeaturesParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.