Skip to content

Commit

Permalink
Merge pull request #981 from okauppinen/describe-layer-wfs
Browse files Browse the repository at this point in the history
Describe layer wfs
  • Loading branch information
ZakarFin authored Aug 14, 2023
2 parents a9ef547 + fd14572 commit 2959663
Show file tree
Hide file tree
Showing 14 changed files with 547 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import fi.nls.oskari.control.layer.PermissionHelper;
import fi.nls.oskari.domain.map.OskariLayer;
import fi.nls.oskari.domain.map.style.VectorStyle;
import fi.nls.oskari.domain.map.wfs.WFSLayerAttributes;
import fi.nls.oskari.domain.map.wfs.WFSLayerOptions;
import fi.nls.oskari.log.LogFactory;
import fi.nls.oskari.log.Logger;
import fi.nls.oskari.map.geometry.WKTHelper;
Expand All @@ -15,24 +17,19 @@
import fi.nls.oskari.map.style.VectorStyleService;
import fi.nls.oskari.service.OskariComponentManager;
import fi.nls.oskari.service.ServiceRuntimeException;
import fi.nls.oskari.util.ConversionHelper;
import fi.nls.oskari.util.JSONHelper;
import fi.nls.oskari.util.ResponseHelper;
import fi.nls.oskari.util.WFSConversionHelper;
import fi.nls.oskari.util.*;
import org.json.JSONObject;
import org.oskari.capabilities.CapabilitiesService;
import org.oskari.capabilities.ogc.LayerCapabilitiesWFS;
import org.oskari.capabilities.ogc.LayerCapabilitiesWMTS;
import org.oskari.capabilities.ogc.wfs.FeaturePropertyType;
import org.oskari.capabilities.ogc.wmts.TileMatrixLink;
import org.oskari.control.layer.model.FeatureProperties;
import org.oskari.control.layer.model.LayerExtendedOutput;
import org.oskari.control.layer.model.LayerOutput;
import org.oskari.permissions.PermissionService;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;

import static fi.nls.oskari.control.ActionConstants.PARAM_ID;
import static fi.nls.oskari.control.ActionConstants.PARAM_SRS;
Expand Down Expand Up @@ -92,6 +89,7 @@ private LayerExtendedOutput getLayerDetails(ActionParameters params, OskariLayer
final String lang = params.getLocale().getLanguage();
final String crs = params.getHttpParam(PARAM_SRS);
final int layerId = layer.getId();
final String layerType = layer.getType();

LayerExtendedOutput output = new LayerExtendedOutput();
output.id = layerId;
Expand All @@ -102,53 +100,82 @@ private LayerExtendedOutput getLayerDetails(ActionParameters params, OskariLayer
}
if (VectorStyleHelper.isVectorLayer(layer)) {
output.styles = getVectorStyles(params, layerId);
output.properties = getProperties(layer, lang);
output.hover = JSONHelper.getObjectAsMap(layer.getOptions().optJSONObject("hover"));
}
if (OskariLayer.TYPE_WMTS.equals(layer.getType())) {
if (OskariLayer.TYPE_WFS.equals(layerType)) {
setDetailsForWFS(output, layer, lang);
}
if (OskariLayer.TYPE_WMTS.equals(layerType)) {
output.capabilities = getCapabilitiesJSON(layer, crs);
}
return output;
}

private List<FeatureProperties> getProperties(OskariLayer layer, String lang) {
if (!OskariLayer.TYPE_WFS.equals(layer.getType())) {
return null;
}
private void setDetailsForWFS (LayerExtendedOutput output, OskariLayer layer, String lang) {
// UserDataLayers are handled in frontend by WFS plugin and embedded myplaces is using WFS type
// so LayerJSONFormatterUSERDATA gathers values from options and attributes in same way than this
LayerCapabilitiesWFS caps = CapabilitiesService.fromJSON(layer.getCapabilities().toString(), layer.getType());
WFSLayerAttributes attr = new WFSLayerAttributes(layer.getAttributes());
WFSLayerOptions opts = new WFSLayerOptions(layer.getOptions());
output.properties = getProperties(caps, attr, lang);
output.controlData = getControlData(caps, attr, opts);
}

private List<FeatureProperties> getProperties(LayerCapabilitiesWFS caps, WFSLayerAttributes attr , String lang) {
List<FeatureProperties> props = new ArrayList<>();

JSONObject locale = getPropertiesLocale(layer);
List<String> selected = attr.getSelectedAttributes(lang);
JSONObject locale = attr.getLocalization(lang).orElse(new JSONObject());
JSONObject format = attr.getFieldFormatMetadata().orElse(new JSONObject());

caps.getFeatureProperties().stream().forEach(prop -> {
FeatureProperties p = new FeatureProperties();
p.name = prop.name;
p.type = WFSConversionHelper.getSimpleType(prop.type);
p.rawType = prop.type;
p.label = getLabelForProperty(locale, prop.name, lang);
p.label = locale.optString(prop.name, null);
p.format = getPropertyFormat(format, prop.name);
if (!selected.isEmpty()) {
int index = selected.indexOf(p.name);
if (index == -1) {
p.hidden = true;
p.order = selected.size();
} else {
p.order = index;
}
}
props.add(p);
});
if (!selected.isEmpty()) {
props.sort(Comparator.comparingInt(a -> a.order));
}
return props;
}
private JSONObject getPropertiesLocale(OskariLayer layer) {
JSONObject attrs = layer.getAttributes();
if (attrs == null) {
return null;
}
JSONObject data = attrs.optJSONObject("data");
if (data == null) {
return null;
}
return data.optJSONObject("locale");
private Map<String, Object> getPropertyFormat (JSONObject format, String name) {
JSONObject propFormat = format.optJSONObject(name);
// return null if doesn't exist
return propFormat != null ? JSONHelper.getObjectAsMap(propFormat) : null;
}

private String getLabelForProperty(JSONObject locale, String prop, String lang) {
if (locale == null) {
return null;
}
JSONObject labelsForLang = locale.optJSONObject(lang);
if (labelsForLang == null) {
return null;
private Map<String, Object> getControlData (LayerCapabilitiesWFS caps, WFSLayerAttributes attr, WFSLayerOptions opts) {
Map<String, Object> data = new HashMap<>();

JSONObject attrData = attr.getAttributesData();
data.put(WFSLayerAttributes.KEY_NO_DATA_VALUE, attr.getNoDataValue());
data.put(WFSLayerAttributes.KEY_COMMON_ID, attr.getCommonId());
data.put(WFSLayerAttributes.KEY_ID_PROPERTY, attrData.optString(WFSLayerAttributes.KEY_ID_PROPERTY, null));

// TODO: should admin store geometryType => styleType
String styleType = attrData.optString(WFSLayerAttributes.KEY_GEOMETRY_TYPE, null);
if (styleType == null) {
String geomName = caps.getGeometryField();
FeaturePropertyType fpt = caps.getFeatureProperty(geomName);
styleType = WFSConversionHelper.getStyleType(fpt.type);
}
return labelsForLang.optString(prop, null);
data.put(WFSLayerAttributes.KEY_STYLE_TYPE, styleType);

data.put(WFSLayerOptions.KEY_RENDER_MODE, opts.getRenderMode());
data.put(WFSLayerOptions.KEY_CLUSTER, opts.getClusteringDistance());
return data;
}

private List<VectorStyle> getVectorStyles (ActionParameters params, int layerId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package org.oskari.control.layer.model;

import com.fasterxml.jackson.annotation.JsonIgnore;

import java.util.Map;

public class FeatureProperties {
public String name;
public String type;
public String rawType;
public String label;
public boolean hidden;
public Map<String,Object> format;
@JsonIgnore
public int order;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ public class LayerExtendedOutput extends LayerOutput {

public String coverage;
public List<VectorStyle> styles;
public Map<String, Object> hover;
public Map<String, Object> capabilities;

public List<FeatureProperties> properties;
public Map<String, Object> controlData;
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,23 @@
* "id_nro": "ID No."
* }
* },
* "format": {
* "kunta_fi": {
* "type": "link"
* },
* "id_nro": {
* "skipEmpty": true,
* "type": "number"
* },
* "grd_id": {
* "type": "link"
* }
* },
* "noDataValue": -1,
* "commonId": "grd_id",
* "wpsInputType": "gs_vector"
* "geometryType": GeometryType,
* "styleType": "point" || "line" || "area" || "collection"
* "idProperty": "id_nro"
* },
* "maxFeatures": 100,
* "namespaceURL": "http://oskari.org"
Expand All @@ -63,7 +77,11 @@ public class WFSLayerAttributes {
public static final String KEY_MAXFEATURES = "maxFeatures";
public static final String KEY_NO_DATA_VALUE = "noDataValue";
public static final String KEY_COMMON_ID = "commonId";
public static final String KEY_WPS_TYPE = "wpsType";

public static final String KEY_STYLE_TYPE = "styleType";
// TODO: should admin store geometryType => styleType
public static final String KEY_GEOMETRY_TYPE = "geometryType";
public static final String KEY_ID_PROPERTY = "idProperty";

private Map<String, List<String>> params = new HashMap<>();
private JSONObject locales = null;
Expand Down Expand Up @@ -133,7 +151,8 @@ public List<String> getSelectedAttributes() {

public List<String> getSelectedAttributes(String lang) {
return params.getOrDefault(lang,
params.getOrDefault(PropertyUtil.getDefaultLanguage(), Collections.emptyList()));
params.getOrDefault("default",
params.getOrDefault(PropertyUtil.getDefaultLanguage(), Collections.emptyList())));
}

public String getNamespaceURL() {
Expand Down Expand Up @@ -171,4 +190,8 @@ public JSONObject getAttributesData() {
JSONObject data = JSONHelper.getJSONObject(attributes, "data");
return data == null ? new JSONObject() : data;
}
public Optional<JSONObject> getFieldFormatMetadata () {
JSONObject format = getAttributesData().optJSONObject("format");
return format == null ? Optional.empty() : Optional.of(format);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
* }
*/
public class WFSLayerOptions {
private static final String KEY_RENDER_MODE = "renderMode";
private static final String KEY_CLUSTER = "clusteringDistance";
public static final String KEY_RENDER_MODE = "renderMode";
public static final String KEY_CLUSTER = "clusteringDistance";
private static final String KEY_HOVER = "hover";
private static final String KEY_LABEL = "labelProperty";
private static final String KEY_STYLES = "styles";
private static final String KEY_DEFAULT_STYLE = "default";
Expand Down Expand Up @@ -78,15 +79,20 @@ public void setDefaultFeatureStyle(JSONObject style) {
}
JSONHelper.putValue(defaultStyle, KEY_FEATURE_STYLE, style);
}
public JSONObject getDefaultFeatureStyle () {
public JSONObject getDefaultStyle () {
JSONObject styles = JSONHelper.getJSONObject(options, KEY_STYLES);
JSONObject defaultStyle = JSONHelper.getJSONObject(styles, KEY_DEFAULT_STYLE);
JSONObject featureStyle = JSONHelper.getJSONObject(defaultStyle, KEY_FEATURE_STYLE);
if (featureStyle == null) {
if (defaultStyle != null) {
// all UserDataLayer should have one 'default' named style with featureStyle definitions
return getDefaultOskariStyle();
return defaultStyle;
}
return featureStyle;
return JSONHelper.createJSONObject(KEY_FEATURE_STYLE, getDefaultOskariStyle());
}
public JSONObject getDefaultFeatureStyle () {
JSONObject defaultStyle = getDefaultStyle();
return defaultStyle.has(KEY_FEATURE_STYLE)
? JSONHelper.getJSONObject(defaultStyle, KEY_FEATURE_STYLE)
: getDefaultOskariStyle();
}
/*-- Common --*/
public void setProperty (String key, Object value) {
Expand All @@ -105,6 +111,7 @@ public int getClusteringDistance() {
public void setClusteringDistance (int cluster) {
JSONHelper.putValue(options, KEY_CLUSTER, cluster);
}
public JSONObject getHover () { return options.optJSONObject(KEY_HOVER); }

// fallback for VectorStyleService and UserDataLayer getDefaultFeatureStyle
public static JSONObject getDefaultOskariStyle () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ public class WFSConversionHelper {
public static final String BOOLEAN = "boolean";
public static final String GEOMETRY = "geometry";
public static final String UNKNOWN = "unknown";
public static final String TYPE_COLLECTION = "collection";
public static final String TYPE_POINT = "point";
public static final String TYPE_LINE = "line";
public static final String TYPE_AREA = "area";

private static final Set<String> NUMBER_TYPES = new HashSet<>(
Arrays.asList("double",
"float",
Expand All @@ -19,15 +24,15 @@ public class WFSConversionHelper {
"number",
"integer",
"long",
"negativeInteger",
"nonNegativeInteger",
"nonPositiveInteger",
"positiveInteger",
"negativeinteger",
"nonnegativeinteger",
"nonpositiveinteger",
"positiveinteger",
"short",
"unsignedLong",
"unsignedInt",
"unsignedShort",
"unsignedByte"
"unsignedlong",
"unsignedint",
"unsignedshort",
"unsignedbyte"
)
);
private static final Set<String> GEOMETRY_TYPES = new HashSet<>(
Expand Down Expand Up @@ -67,20 +72,42 @@ public static boolean isGeometryType (String type) {
return GEOMETRY_TYPES.contains(type);
}
public static String getSimpleType (String type) {
if (type == null) {
return UNKNOWN;
}
if (isGeometryType(type)) {
return GEOMETRY;
}
if (isStringType(type)) {
String lower = type.toLowerCase();
if (isStringType(lower)) {
return STRING;
}
if (isNumberType(type)) {
if (isNumberType(lower)) {
return NUMBER;
}
if (isBooleanType(type)) {
if (isBooleanType(lower)) {
return BOOLEAN;
}
return UNKNOWN;
}

public static String getStyleType (String rawGeometryType) {
if (rawGeometryType == null) {
return UNKNOWN;
}
String lower = rawGeometryType.toLowerCase();
if (lower.contains("surface") || lower.contains("polygon")) {
return TYPE_AREA;
}
if (lower.contains(TYPE_POINT)) {
return TYPE_POINT;
}
if (lower.contains(TYPE_LINE)) {
return TYPE_LINE;
}
return TYPE_COLLECTION;
}

public static String getStringOrNumber (String type) {
return isNumberType(type) ? NUMBER : STRING;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class LayerJSONFormatter {
protected static final String KEY_LOCALIZED_NAME = "name"; // FIXME: title
protected static final String KEY_SUBTITLE = "subtitle";
protected static final String KEY_OPTIONS = "options";
protected static final String KEY_ATTRIBUTES = "attributes";
protected static final String KEY_DATA_PROVIDER = "orgName";
protected static final String[] STYLE_KEYS ={"name", "title", "legend"};

Expand Down Expand Up @@ -140,13 +141,12 @@ public JSONObject getBaseJSON(final OskariLayer layer,
if(layer.getMaxScale() != null && layer.getMaxScale() != -1) {
JSONHelper.putValue(layerJson, "maxScale", layer.getMaxScale());
}
JSONObject attributes = layer.getAttributes();
if (!useProxy) {
// don't write additional params for proxied urls
JSONHelper.putValue(layerJson, "params", layer.getParams());
}
JSONHelper.putValue(layerJson, KEY_OPTIONS, layer.getOptions());
JSONHelper.putValue(layerJson, "attributes", attributes);
JSONHelper.putValue(layerJson, KEY_ATTRIBUTES, layer.getAttributes());

JSONHelper.putValue(layerJson, "realtime", layer.getRealtime());
JSONHelper.putValue(layerJson, "refreshRate", layer.getRefreshRate());
Expand Down
Loading

0 comments on commit 2959663

Please sign in to comment.