Skip to content

Commit

Permalink
started on subfeature span insertion with integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
turingtestfail committed Jun 19, 2024
1 parent dcdf3d5 commit 8deaee4
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
import static org.geoserver.mapml.MapMLConstants.MAPML_SKIP_STYLES_FO;
import static org.geoserver.mapml.MapMLConstants.MAPML_USE_FEATURES;
import static org.geoserver.mapml.MapMLConstants.MAPML_USE_TILES;
import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_HEAD_FTL;
import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_PREVIEW_HEAD_FTL;
import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_XML_HEAD_FTL;

import freemarker.template.TemplateMethodModelEx;
import java.io.IOException;
Expand Down Expand Up @@ -121,7 +121,6 @@ public class MapMLDocumentBuilder {
private static final int BYTES_PER_PIXEL_TRANSPARENT = 4;
private static final int BYTES_PER_KILOBYTE = 1024;
public static final String DEFAULT_MIME_TYPE = "image/png";
public static final String MAPML_XML_HEAD_FTL = "mapml-head.ftl";

private final WMS wms;

Expand Down Expand Up @@ -901,7 +900,7 @@ private HeadContent prepareHead() throws IOException {
}
String styles = buildStyles();
// get the styles and links from the head template
List<String> stylesAndLinks = getHeaderTemplates(MAPML_HEAD_FTL, getFeatureTypes());
List<String> stylesAndLinks = getHeaderTemplates(MAPML_XML_HEAD_FTL, getFeatureTypes());
styles = appendStylesFromHeadTemplate(styles, stylesAndLinks);
if (styles != null) head.setStyle(styles);
links.addAll(getLinksFromHeadTemplate(stylesAndLinks));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static org.geoserver.mapml.MapMLConstants.MAPML_FEATURE_FO;
import static org.geoserver.mapml.MapMLConstants.MAPML_SKIP_ATTRIBUTES_FO;
import static org.geoserver.mapml.MapMLConstants.MAPML_SKIP_STYLES_FO;
import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_FEATURE_FTL;

import java.io.IOException;
import java.util.ArrayList;
Expand All @@ -25,6 +26,7 @@
import org.geoserver.gwc.layer.GeoServerTileLayer;
import org.geoserver.mapml.tcrs.TiledCRSConstants;
import org.geoserver.mapml.tcrs.TiledCRSParams;
import org.geoserver.mapml.template.MapMLMapTemplate;
import org.geoserver.mapml.xml.BodyContent;
import org.geoserver.mapml.xml.Feature;
import org.geoserver.mapml.xml.HeadContent;
Expand All @@ -37,6 +39,7 @@
import org.geoserver.ows.URLMangler;
import org.geoserver.ows.util.ResponseUtils;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.featureinfo.FeatureTemplate;
import org.geotools.api.feature.simple.SimpleFeature;
import org.geotools.api.referencing.FactoryException;
import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
Expand All @@ -56,6 +59,7 @@ public class MapMLFeatureUtil {
public static final String STYLE_CLASS_PREFIX = ".";
public static final String STYLE_CLASS_DELIMITER = " ";
public static final String BBOX_DISPLAY_NONE = ".bbox {display:none}";
private static final MapMLMapTemplate mapMLMapTemplate = new MapMLMapTemplate();

/**
* Convert a feature collection to a MapML document
Expand Down Expand Up @@ -91,6 +95,11 @@ public static Mapml featureCollectionToMapML(
throw new ServiceException("MapML OutputFormat does not support Complex Features.");
}
SimpleFeatureCollection fc = (SimpleFeatureCollection) featureCollection;
boolean hasTemplate = false;
if (!mapMLMapTemplate.isTemplateEmpty(
fc.getSchema(), MAPML_FEATURE_FTL, FeatureTemplate.class, "0\n")) {
hasTemplate = true;
}

ResourceInfo resourceInfo = layerInfo.getResource();
MetadataMap layerMeta = resourceInfo.getMetadata();
Expand Down Expand Up @@ -151,6 +160,9 @@ public static Mapml featureCollectionToMapML(
try (SimpleFeatureIterator iterator = fc.features()) {
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
if (hasTemplate) {
String templateOutput = mapMLMapTemplate.features(fc.getSchema(), feature);
}
// convert feature to xml
if (styles != null) {
List<MapMLStyle> applicableStyles = getApplicableStyles(feature, styles);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,32 @@
import org.geoserver.catalog.Catalog;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.template.DirectTemplateFeatureCollectionFactory;
import org.geoserver.template.FeatureWrapper;
import org.geoserver.template.GeoServerTemplateLoader;
import org.geoserver.template.TemplateUtils;
import org.geoserver.wms.featureinfo.FeatureTemplate;
import org.geotools.api.feature.Feature;
import org.geotools.api.feature.simple.SimpleFeature;
import org.geotools.api.feature.simple.SimpleFeatureType;
import org.geotools.api.feature.type.FeatureType;
import org.geotools.feature.FeatureCollection;

/** A template engine for generating MapML content. */
public class MapMLMapTemplate {
/** The template configuration */
static Configuration templateConfig;

static DirectTemplateFeatureCollectionFactory FC_FACTORY =
new DirectTemplateFeatureCollectionFactory();

static {
// initialize the template engine, this is static to maintain a cache
templateConfig = TemplateUtils.getSafeConfiguration();

templateConfig.setLocale(Locale.US);
templateConfig.setNumberFormat("0.###########");
templateConfig.setObjectWrapper(new FeatureWrapper(FC_FACTORY));

// encoding
templateConfig.setDefaultEncoding("UTF-8");
Expand All @@ -43,7 +53,9 @@ public class MapMLMapTemplate {
public static final String MAPML_PREVIEW_HEAD_FTL = "mapml-preview-head.ftl";

/** The template used to add to the head of the xml representation */
public static final String MAPML_HEAD_FTL = "mapml-head.ftl";
public static final String MAPML_XML_HEAD_FTL = "mapml-head.ftl";

public static final String MAPML_FEATURE_FTL = "mapml-feature.ftl";

/** Template cache used to avoid paying the cost of template lookup for each GetMap call */
Map<MapMLMapTemplate.TemplateKey, Template> templateCache = new HashMap<>();
Expand Down Expand Up @@ -81,6 +93,18 @@ public String preview(SimpleFeatureType featureType) throws IOException {
return caw.toString();
}

public String features(SimpleFeatureType featureType, SimpleFeature feature)
throws IOException {
caw.reset();
features(featureType, feature, caw);
return caw.toString();
}

public void features(SimpleFeatureType featureType, SimpleFeature feature, Writer writer)
throws IOException {
execute(feature, featureType, writer, MAPML_FEATURE_FTL);
}

/**
* Generates the head content for the given feature type.
*
Expand All @@ -91,7 +115,7 @@ public String preview(SimpleFeatureType featureType) throws IOException {
*/
public void head(Map<String, Object> model, SimpleFeatureType featureType, Writer writer)
throws IOException {
execute(model, featureType, writer, MAPML_HEAD_FTL);
execute(model, featureType, writer, MAPML_XML_HEAD_FTL);
}

/**
Expand Down Expand Up @@ -131,6 +155,24 @@ private void execute(
}
}

/*
* Internal helper method to exceute the template against feature or
* feature collection.
*/
private void execute(
Feature feature, SimpleFeatureType featureType, Writer writer, String template)
throws IOException {

Template t = lookupTemplate(featureType, template, null);

try {
t.process(feature, writer);
} catch (TemplateException e) {
String msg = "Error occured processing template.";
throw (IOException) new IOException(msg).initCause(e);
}
}

/**
* Returns the template for the specified feature type. Looking up templates is pretty
* expensive, so we cache templates by feture type and template.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,25 @@

import static org.geoserver.mapml.MapMLConstants.MAPML_USE_FEATURES;
import static org.geoserver.mapml.MapMLConstants.MAPML_USE_TILES;
import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_FEATURE_FTL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.awt.Rectangle;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.xml.bind.JAXBElement;

import org.apache.commons.io.FileUtils;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogBuilder;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerGroupInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.data.test.MockData;
Expand Down Expand Up @@ -289,6 +294,71 @@ public void testMapMLGetStyleQuery() throws Exception {
qElse.getFilter().toString().contains("ADDRESS = 123 Main Street"));
}

@Test
public void testMapMLFeatureHasClass() throws Exception {
File template = null;
try {
Catalog cat = getCatalog();
LayerInfo li = cat.getLayerByName(MockData.BUILDINGS.getLocalPart());
li.getResource().getMetadata().put(MAPML_USE_FEATURES, true);
li.getResource().getMetadata().put(MAPML_USE_TILES, false);
cat.save(li);
String layerId = getLayerId(MockData.BUILDINGS);
FeatureTypeInfo resource =
getCatalog().getResourceByName(layerId, FeatureTypeInfo.class);
File parent = getDataDirectory().get(resource).dir();
template = new File(parent, MAPML_FEATURE_FTL);
FileUtils.write(
template,
"<map-head>\n"
+ " <map-style>.desired {stroke-dashoffset:3}</map-style>\n"
+ "</map-head>\n"
+ " <#list attributes as attribute>\n"
+ " <#if attribute.name == \"ADDRESS\">\n"
+ " <map-property name=\"UPDATED ${attribute.name}\" value=\"CHANGED ${attribute.value}\"/>\n"
+ " <#elseif !attribute.isGeometry>\n"
+ " <map-property name=\"${attribute.name}\" value=\"${attribute.value}\"/>\n"
+ " </#if>\n"
+ " <#if attribute.isGeometry>\n"
+ " <map-polygon>\n"
+ " <map-coordinates>\n"
+ " <#list attribute.rawValue.coordinates as coord>\n"
+ " <#if coord?index == 3>\n"
+ " <span class=\"desired\">${coord.x} ${coord.y}\n"
+ " <#elseif coord?index == 4>\n"
+ " ${coord.x} ${coord.y}</span>\n"
+ " <#else>\n"
+ " ${coord.x} ${coord.y}\n"
+ " </#if>\n"
+ " </#list>\n"
+ " </map-coordinates>\n"
+ " </map-polygon>\n"
+ " </#if>\n"
+ " </#list>\n",
"UTF-8");
Mapml mapmlFeatures =
new MapMLWMSRequest()
.name(MockData.BUILDINGS.getLocalPart())
.bbox("-180,-90,180,90")
.srs("EPSG:4326")
.feature(true)
.getAsMapML();

String mapmlStyle = mapmlFeatures.getHead().getStyle();

Feature feature2 =
mapmlFeatures
.getBody()
.getFeatures()
.get(1); // get the second feature, which has a class
assertEquals("desired", feature2.getStyle());
} finally {
if (template != null) {
template.delete();
}
}
}

@Test
public void testExceptionBecauseMoreThanOneFeatureType() throws Exception {
Catalog cat = getCatalog();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.geoserver.mapml.MapMLConstants.MAPML_USE_FEATURES;
import static org.geoserver.mapml.MapMLConstants.MAPML_USE_TILES;
import static org.geoserver.mapml.MapMLDocumentBuilder.MAPML_XML_HEAD_FTL;
import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_PREVIEW_HEAD_FTL;
import static org.geoserver.mapml.template.MapMLMapTemplate.MAPML_XML_HEAD_FTL;
import static org.geowebcache.grid.GridSubsetFactory.createGridSubSet;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.startsWith;
Expand Down

0 comments on commit 8deaee4

Please sign in to comment.