/** * */ package org.gcube.portlets.user.geoportaldataviewer.server.gis; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; import org.gcube.application.geoportalcommon.shared.gis.BoundsMap; import org.gcube.application.geoportalcommon.util.URLParserUtil; import org.gcube.portlets.user.geoportaldataviewer.client.GeoportalDataViewerConstants; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.LayerItem; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.wfs.FeatureGeometry; import org.gcube.portlets.user.geoportaldataviewer.shared.gis.wfs.FeatureRow; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The Class FeatureParser. * * @author Francesco Mangiacrapa at ISTI-CNR (francesco.mangiacrapa@isti.cnr.it) * * Nov 13, 2020 */ public class FeatureParser { private static Logger LOG = LoggerFactory.getLogger(FeatureParser.class); /** * Gets the WFS features. * * @param layerItem the layer item * @param mapSrsName the map srs name * @param selectBBOX the select BBOX * @param maxWFSFeature the max WFS feature * @return the WFS features */ public static List getWFSFeatures(LayerItem layerItem, String mapSrsName, BoundsMap selectBBOX, int maxWFSFeature) { if (maxWFSFeature < 0) { maxWFSFeature = GeoportalDataViewerConstants.MAX_WFS_FEATURES; } return getWFSFeatureProperties(layerItem, mapSrsName, selectBBOX, maxWFSFeature); } /** * Gets the WFS feature properties. * * @param layerItem the layer item * @param mapSrsName the map srs name * @param selectBBOX the select BBOX * @param maxWFSFeature the max WFS feature * @return the WFS feature properties */ @SuppressWarnings("unchecked") private static List getWFSFeatureProperties(LayerItem layerItem, String mapSrsName, BoundsMap selectBBOX, int maxWFSFeature) { LOG.info("getWFSFeatureProperties for layerItem: " + layerItem.getName() + " in the " + selectBBOX + " and maxWFSFeature: " + maxWFSFeature); InputStream is = null; List listFeaturesRow = new ArrayList(); try { String url = GisMakers.buildWFSFeatureQuery(layerItem, mapSrsName, selectBBOX, maxWFSFeature, GisMakers.JSON); String cqlFilterValue = URLParserUtil.extractValueOfParameterFromURL(GisMakers.CQL_FILTER_PARAMETER, url); LOG.info("Found CQL filter value into query string: " + cqlFilterValue); if (cqlFilterValue != null) { String notEncodedCQLFilter = String.format("%s=%s", GisMakers.CQL_FILTER_PARAMETER, cqlFilterValue); // log.info("Found CQL filter: "+notEncodedCQLFilter); String toEncodeCQLFilter = String.format("%s=%s", GisMakers.CQL_FILTER_PARAMETER, URLEncoder.encode(cqlFilterValue, "UTF-8")); LOG.debug("Encoded CQL filter: " + toEncodeCQLFilter); url = url.replace(notEncodedCQLFilter, toEncodeCQLFilter); } LOG.info("Built WFS URL: " + url); is = new URL(url).openStream(); String jsonTxt = IOUtils.toString(is); if (jsonTxt == null || jsonTxt.isEmpty()) { jsonTxt = "{\"type\":\"FeatureCollection\",\"features\":[]}"; } // get json object JSONObject json = new JSONObject(jsonTxt); // iterate features JSONArray features = json.getJSONArray("features"); if (features.length() == 0) { LOG.info("No features detected in the response, returning empty list"); return listFeaturesRow; } String featureCRSName = ""; try { JSONObject crs = json.getJSONObject("crs"); JSONObject crsProp = crs.getJSONObject("properties"); featureCRSName = crsProp.getString("name"); LOG.info("Crs name found: " + featureCRSName); } catch (Exception e) { LOG.warn("Unable to read the field 'crs'"); } LOG.info("Features are: " + features.length()); for (int i = 0; i < features.length(); i++) { final FeatureRow row = new FeatureRow(); row.setCrsName(featureCRSName); JSONObject theFeature = ((JSONObject) features.get(i)); LOG.debug("Building at index: " + i); try { String fetaureId = theFeature.getString("id"); row.setId(fetaureId); JSONObject geometry = theFeature.getJSONObject("geometry"); String typeValue = geometry.getString("type"); FeatureGeometry fg = new FeatureGeometry(); fg.setType(typeValue); try { JSONArray coordinates = geometry.getJSONArray("coordinates"); String coordinateJSONString = coordinates.toString(); LOG.debug("coordinates are: " + coordinateJSONString); fg.setCoordinatesJSON(coordinates.toString()); } catch (Exception e) { LOG.warn("Not able to parse the 'coordinates' field: ", e); } row.setGeometry(fg); } catch (Exception e) { LOG.debug("Unable to parse geometry at index: " + i); } // // iterate properties JSONObject properties = theFeature.getJSONObject("properties"); Map> mapProperties = new HashMap>(); @SuppressWarnings("unchecked") Iterator ii = properties.keys(); while (ii.hasNext()) { String key = ii.next(); String value = properties.optString(key, ""); List theValues = mapProperties.get(key); if (theValues == null) mapProperties.put(key, Arrays.asList(value)); else { theValues.add(value); mapProperties.put(key, theValues); } } row.setMapProperties(mapProperties); listFeaturesRow.add(row); LOG.info("Added row " + row + " to exported properties"); } } catch (IOException e) { LOG.error("Error for layerItem name: " + layerItem.getName(), e); } catch (JSONException e) { LOG.error("Error for layerItem name: " + layerItem.getName(), e); } finally { IOUtils.closeQuietly(is); } LOG.info("Returning " + listFeaturesRow.size() + " features"); return listFeaturesRow; } }