Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GEOS-11368] Allow Freemarker templates to update MapML responses #368

Conversation

turingtestfail
Copy link

started on template page

Checklist

For core and extension modules:

  • New unit tests have been added covering the changes.
  • Documentation has been updated (if change is visible to end users).
  • The REST API docs have been updated (when changing configuration objects or the REST controllers).
  • There is an issue in the GeoServer Jira (except for changes that do not affect administrators or end users in any way).
  • Commit message(s) must be in the form [GEOS-XYZWV] Title of the Jira ticket.
  • Bug fixes and small new features are presented as a single commit.
  • Each commit has a single objective (if there are multiple commits, each has a separate JIRA ticket describing its goal).

@turingtestfail turingtestfail force-pushed the GEOS-11368-MapML-FreeMarker branch from 2fbc91a to 7f5007e Compare May 31, 2024 19:05
@turingtestfail turingtestfail force-pushed the GEOS-11368-MapML-FreeMarker branch from 7190732 to 32c7542 Compare June 21, 2024 18:28
<map-geometry>
<map-point>
<map-coordinates><#list gattribute.rawValue.coordinates as coord>
<#if coord?index == 0><![CDATA[<span class="desired">]]>${coord.x} ${coord.y}<![CDATA[</span>]]><#else>${coord.x} ${coord.y}</#if></#list></map-coordinates></map-point>
Copy link
Collaborator

@prushforth prushforth Jul 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be <map-span>. Note that the <span> you've inserted seems to be escaped in the output - maybe you don't wan't the CDATA sections?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Freemarker is rejecting the tags inside of the if logic unless it was escaped. I'll check to see if there is a better workaround.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be . Note that the you've inserted seems to be escaped in the output - maybe you don't wan't the CDATA sections?

Ok, fixed. The switch to list seems to have corrected the issue where CDATA escaping was required.


<mapml- xmlns="http://www.w3.org/1999/xhtml"><map-head><map-title>Bridges</map-title><map-meta charset="UTF-8"/><map-meta content="text/mapml" http-equiv="Content-Type"/><map-meta name="extent" content="top-left-longitude=-180.000000,top-left-latitude=90.000000,bottom-right-longitude=180.000000,bottom-right-latitude=-90.000000"/><map-meta name="cs" content="gcrs"/><map-meta name="projection" content="MapML:urn:ogc:def:crs:EPSG::4326"/><map-style>.bbox {display:none} .Bridges-r1-s1{r:48.0; stroke-opacity:1.0; stroke-dashoffset:0; well-known-name:square; stroke-width:1.0; opacity:1.0; fill:#808080; fill-opacity:1.0; stroke:#000000; stroke-linecap:butt}</map-style></map-head><map-body><map-feature id="Bridges.1107531599613" class="Bridges-r1-s1"><map-geometry><map-point><map-coordinates>&lt;span class="desired">0.0007 0.0002&lt;/span></map-coordinates></map-point></map-geometry><map-properties><table xmlns="http://www.w3.org/1999/xhtml"><thead><tr><th role="columnheader" scope="col">Property name</th><th role="columnheader" scope="col">Property value</th></tr></thead><tbody><tr><th scope="row">FID</th><td itemprop="FID">110</td></tr><tr><th scope="row">NAME</th><td itemprop="NAME">Cam Bridge</td></tr></tbody></table></map-properties></map-feature></map-body></mapml->

Note that in addition to tagging the coordinates with a style class, the template also changes the name of the NAME property to "UPDATED NAME" and the value to "CHANGED Cam Bridge".
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok but the output still has <th scope="row">NAME</th><td itemprop="NAME">Cam Bridge</td></tr>

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

<#list 0 ..< attribute.rawValue.getNumGeometries() as index>
<#assign polygon = attribute.rawValue.getGeometryN(index)>
<map-polygon>
<#assign shell = polygon.getExteriorRing()><map-coordinates><#list shell.coordinates as coord><#if coord?index == 0><![CDATA[<span class="desired">]]>${coord.x} ${coord.y}<#elseif coord?index == 4> ${coord.x} ${coord.y}<![CDATA[</span>]]><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be <map-span>, or feel free to use <map-a href="example.org" target="_top">${coord.x} ${coord.y}</map-a> if you like

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

<map-polygon>
<#assign shell = polygon.getExteriorRing()><map-coordinates><#list shell.coordinates as coord><#if coord?index == 0><![CDATA[<span class="desired">]]>${coord.x} ${coord.y}<#elseif coord?index == 4> ${coord.x} ${coord.y}<![CDATA[</span>]]><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates>
<#list 0 ..< polygon.getNumInteriorRing() as index>
<#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord><#if coord?index == 0><![CDATA[<span class="desired">]]>${coord.x} ${coord.y} <#elseif coord?index == 4> ${coord.x} ${coord.y}<![CDATA[</span>]]><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates></#list>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<map-span>

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@prushforth
Copy link
Collaborator

Thanks for your hard work on this Joe. I tried to run this branch this morning, but geoserver wouldn't start. I'll try again from home tonight.

@turingtestfail
Copy link
Author

Thanks for your hard work on this Joe. I tried to run this branch this morning, but geoserver wouldn't start. I'll try again from home tonight.

@prushforth Any further luck with testing?

@prushforth
Copy link
Collaborator

Any further luck with testing?

I am getting bean creation errors when starting geoserver that prevent it from starting:

10-Jul-2024 16:48:59.964 SEVERE [Catalina-utility-2] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [org.geoserver.platform.GeoServerContextLoaderListener]
	org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gMLPreview' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-web-demo-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'geoServer' while setting bean property 'geoserver'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'geoServer' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'catalog' while setting bean property 'catalog'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'localWorkspaceCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'advertisedCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisedCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'secureCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accessRulesDao' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationSecurityContext.xml]: Cannot resolve reference to bean 'rawCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rawCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.NoSuchFieldError: QUETTA
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1707)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1452)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:209)
		at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
		at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
		at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:591)
		at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:399)
		at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:278)
		at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:103)
		at org.geoserver.platform.GeoServerContextLoaderListener.contextInitialized(GeoServerContextLoaderListener.java:22)
		at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4494)
		at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4946)
		at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
		at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:683)
		at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:658)
		at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:662)
		at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1023)
		at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1910)
		at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
		at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
		at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
		at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:118)
		at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:824)
		at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:474)
		at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1666)
		at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:314)
		at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:123)
		at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1102)
		at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1301)
		at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1305)
		at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1283)
		at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
		at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
		at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
		at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
		at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
		at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
		at java.base/java.lang.Thread.run(Thread.java:829)
	Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'geoServer' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'catalog' while setting bean property 'catalog'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'localWorkspaceCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'advertisedCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisedCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'secureCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accessRulesDao' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationSecurityContext.xml]: Cannot resolve reference to bean 'rawCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rawCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.NoSuchFieldError: QUETTA
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1707)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1452)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:209)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
		... 44 more
	Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'localWorkspaceCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'advertisedCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisedCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'secureCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accessRulesDao' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationSecurityContext.xml]: Cannot resolve reference to bean 'rawCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rawCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.NoSuchFieldError: QUETTA
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
		at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:695)
		at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:209)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
		... 54 more
	Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisedCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'secureCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accessRulesDao' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationSecurityContext.xml]: Cannot resolve reference to bean 'rawCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rawCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.NoSuchFieldError: QUETTA
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
		at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:695)
		at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:209)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
		... 66 more
	Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accessRulesDao' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationSecurityContext.xml]: Cannot resolve reference to bean 'rawCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rawCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.NoSuchFieldError: QUETTA
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
		at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:695)
		at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:209)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:209)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
		... 78 more
	Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rawCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.NoSuchFieldError: QUETTA
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:628)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
		at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:336)
		at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
		at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:334)
		at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:209)
		at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:330)
		... 92 more
	Caused by: java.lang.NoSuchFieldError: QUETTA
		at org.geotools.measure.PrefixDefinitions.<clinit>(PrefixDefinitions.java:52)
		at org.geotools.measure.UnitDefinition.withStandardPrefixes(UnitDefinition.java:47)
		at org.geotools.measure.UnitDefinitions.<clinit>(UnitDefinitions.java:54)
		at org.geotools.measure.WktUnitFormat.<clinit>(WktUnitFormat.java:45)
		at org.geotools.measure.Units.autoCorrect(Units.java:159)
		at org.geotools.referencing.wkt.Parser.parseUnit(Parser.java:399)
		at org.geotools.referencing.wkt.Parser.parseGeoGCS(Parser.java:929)
		at org.geotools.referencing.wkt.Parser.parseCoordinateReferenceSystem(Parser.java:228)
		at org.geotools.referencing.wkt.Parser.parseCoordinateReferenceSystem(Parser.java:210)
		at org.geotools.referencing.factory.ReferencingObjectFactory.createFromWKT(ReferencingObjectFactory.java:1126)
		at org.geotools.referencing.CRS.parseWKT(CRS.java:568)
		at org.geoserver.config.util.XStreamPersister$CRSConverter.fromString(XStreamPersister.java:1480)
		at com.thoughtworks.xstream.converters.SingleValueConverterWrapper.fromString(SingleValueConverterWrapper.java:41)
		at com.thoughtworks.xstream.converters.SingleValueConverterWrapper.unmarshal(SingleValueConverterWrapper.java:49)
		at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:74)
		at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:68)
		at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:499)
		at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:425)
		at org.geoserver.config.util.XStreamPersister$ResourceInfoConverter.doUnmarshal(XStreamPersister.java:2031)
		at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:277)
		at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:74)
		at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:68)
		at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:52)
		at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:136)
		at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
		at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1464)
		at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1441)
		at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1330)
		at org.geoserver.config.util.XStreamPersister.load(XStreamPersister.java:728)
		at org.geoserver.config.GeoServerLoader.depersist(GeoServerLoader.java:1138)
		at org.geoserver.config.GeoServerLoader$LayerLoader.accept(GeoServerLoader.java:200)
		at org.geoserver.config.GeoServerLoader.loadDataStore(GeoServerLoader.java:861)
		at org.geoserver.config.GeoServerLoader.readCatalog(GeoServerLoader.java:664)
		at org.geoserver.config.GeoServerLoader.readCatalog(GeoServerLoader.java:479)
		at org.geoserver.config.DefaultGeoServerLoader.loadCatalog(DefaultGeoServerLoader.java:37)
		at org.geoserver.config.GeoServerLoader.postProcessBeforeInitializationCatalog(GeoServerLoader.java:329)
		at org.geoserver.config.GeoServerLoader.postProcessBeforeInitialization(GeoServerLoader.java:280)
		at org.geoserver.config.GeoServerLoaderProxy.postProcessBeforeInitialization(GeoServerLoaderProxy.java:61)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:440)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)
		at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
		... 98 more
10-Jul-2024 16:48:59.966 INFO [Catalina-utility-2] org.apache.catalina.core.ApplicationContext.log Closing Spring root WebApplicationContext

will play around a bit more

@prushforth
Copy link
Collaborator

Had an application deployed with a different spring version I think. Has started up now, will test it a bit.

@prushforth
Copy link
Collaborator

@turingtestfail sorry bit of confusion on my part, but I was only able to start the server when I had no data in the geoserver data dir. When I try to start with the data from the release profile, I get the spring GML preview bean error above, geoserver won't start.

@prushforth
Copy link
Collaborator

OK after more messing about I got the server to start. I had to git pull upstream main --rebase and re-build. I will try to test it now.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The viewer is returned when the format includes subtype=mapml. The viewer is an HTML document that includes a head section with a link to the stylesheet. The default viewer is a simple viewer that includes a link to the default stylesheet.
A template can be created to insert links to whole stylesheet or actual stylesheet elements.
We can do this by creating a file called ``mapml-head-viewer.ftl`` in the GeoServer data directory in the directory for the layer that we wish to append links to. For example we could create this file under ``workspaces/topp/states_shapefile/states``. To add stylesheet links and stylesheet elements, we enter the following text inside this new file:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be mapml-preview-head.ftl


GetMap XML Head Stylesheet Templating
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
MapML in XML format includes a map-head element that includes map-link elements to link to other resources, including map style variants. Additional map-link elements can be added to the map-head element by creating a mapml-head.ftl template in the GeoServer data directory in the directory for the layer we wish to append map-links to. For example we could create the head.ftl file under ``workspaces/tiger/poly_landmarks_shapefile/poly_landmarks``:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be workspaces/tiger/nyc/poly_landmarks ? But when I locate a mapml-head.ftl in that directory per line 58 below, I don't see it in the output. Not sure if it's me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it was me and the software: the output is created, but doesn't match the documentation on lines 79-82 below. What appears is this:

<map-link
            href="http://localhost:8080/geoserver/topp/wms?REQUEST=GetMap&amp;FORMAT=text%2Fmapml&amp;SRS=MapML%3AWGS84&amp;FORMAT_OPTIONS=%7BMAPML-WMS-FORMAT%3Dimage%2Fpng%7D&amp;BBOX=SRSEnvelope%5B-124.73142200000001%20%3A%20-66.969849%2C%2024.955967%20%3A%2049.371735%5D&amp;VERSION=1.3.0&amp;STYLES=population&amp;SERVICE=WMS&amp;WIDTH=330&amp;HEIGHT=768&amp;LAYERS=states"
            rel="style" title="templateinsertedstyle" />
        <map-style>.bbox {display:none} .population-r1-s1{fill:#4DFF4D; fill-opacity:0.7}
            .population-r2-s1{fill:#FF4D4D; fill-opacity:0.7} .population-r3-s1{fill:#4D4DFF;
            fill-opacity:0.7} .population-r4-s1{stroke-opacity:1.0; stroke-dashoffset:0;
            stroke-width:0.2; stroke:#000000; stroke-linecap:butt}
            .polygon-r1-s1{stroke-opacity:3.0; stroke-dashoffset:4; stroke-width:2.0; fill:#AAAAAA;
            fill-opacity:3.0; stroke:#DD0000; stroke-linecap:butt}</map-style>

So the styles are merged, and the comments don't appear. I think that the template should create a new <map-style> but maybe this is something to do with marshaling or unmarshaling I can never remember which is which.

Copy link
Collaborator

@prushforth prushforth Jul 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In mapml-features-head.ftl I also notice that the <map-style> elements in the template are merged into the end of the <map-style> that is created, at minimum creating some variance with the documentation.


A more complex example mapml-feature.ftl that operates on a multi-polygon layer and only inserts map-span tags into a specific feature::

<mapml- xmlns=\"http://www.w3.org/1999/xhtml\">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried the previous examples and got them to work, +/- any comments above. I think this example is the most complex so it would be ideal to make it work for one of the release layers, such as poly_landmarks. So far I haven't got it to have a visible effect though. One barrier is having to restart the server after each change to an .ftl file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried the previous examples and got them to work, +/- any comments above. I think this example is the most complex so it would be ideal to make it work for one of the release layers, such as poly_landmarks. So far I haven't got it to have a visible effect though. One barrier is having to restart the server after each change to an .ftl file.

I just pushed some udpates that should help:
1)There was an issue with the non-geospatial attributes not getting updated that should be resolved.
2)I have added several more examples, covering all of the geometry types
3)I fixed an issue with geometrycollection parsing and added an example to the documentation.

With regards to the requirement to restart when the template is updated - that is required for performance reasons. The template gets cached after the first time it gets used. I can change that but there will be a performance penalty. A possible compromise would be to hash the template and then monitor for changes - another performance penalty, but smaller than replacing it with every call.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With regards to the requirement to restart when the template is updated - that is required for performance reasons.

I can live with it. It would be great if there was a debugging window in GeoServer where you could paste a ftl and see if it worked before saving it somewhere.

I tried this template from your updated examples with poi:

<mapml- xmlns="http://www.w3.org/1999/xhtml">
  <map-head>
  </map-head>
  <map-body>
    <map-feature>
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-geometrycollection>
              <map-linestring><map-coordinates><#list attribute.rawValue.coordinates as coord>${coord.x} ${coord.y}</#list></map-coordinates></map-linestring>
              <map-point><map-coordinates><#list attribute.rawValue.coordinates as coord>${coord.x} ${coord.y}</#list></map-coordinates></map-point>
            </map-geometrycollection>
          </map-geometry>
        </#if>
      </#list>
    </map-feature>
  </map-body>
</mapml->

And I get this exception:

<?xml version="1.0" encoding="UTF-8"?><ServiceExceptionReport version="1.3.0" xmlns="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ogc http://localhost:8080/geoserver/schemas/wms/1.3.0/exceptions_1_3_0.xsd">   <ServiceException>
      javax.xml.bind.UnmarshalException
 - with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 15; unexpected element (uri:&quot;http://www.w3.org/1999/xhtml&quot;, local:&quot;map-point&quot;). Expected elements are &lt;{http://www.w3.org/1999/xhtml}point&gt;,&lt;{http://www.w3.org/1999/xhtml}map-linestring&gt;,&lt;{http://www.w3.org/1999/xhtml}map-polygon&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multipoint&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multilinestring&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multipolygon&gt;]
Exception Description: An error occurred unmarshalling the document
Internal Exception: org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 15; unexpected element (uri:&quot;http://www.w3.org/1999/xhtml&quot;, local:&quot;map-point&quot;). Expected elements are &lt;{http://www.w3.org/1999/xhtml}point&gt;,&lt;{http://www.w3.org/1999/xhtml}map-linestring&gt;,&lt;{http://www.w3.org/1999/xhtml}map-polygon&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multipoint&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multilinestring&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multipolygon&gt;
unexpected element (uri:&quot;http://www.w3.org/1999/xhtml&quot;, local:&quot;map-point&quot;). Expected elements are &lt;{http://www.w3.org/1999/xhtml}point&gt;,&lt;{http://www.w3.org/1999/xhtml}map-linestring&gt;,&lt;{http://www.w3.org/1999/xhtml}map-polygon&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multipoint&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multilinestring&gt;,&lt;{http://www.w3.org/1999/xhtml}map-multipolygon&gt;
</ServiceException></ServiceExceptionReport>

I like the fact that the examples are tied to specific release layers so I can work from an example that I know is supposed to work (my freemarker skills are what any beginner would be capable of).

@turingtestfail
Copy link
Author

turingtestfail commented Jul 15, 2024 via email

@prushforth
Copy link
Collaborator

ok this may be progress, or maybe not.

I am trying to get the polygon / span template working on the nyc poly_landmarks layer working. I have this template so far, changed from your original example:

<mapml- xmlns="http://www.w3.org/1999/xhtml">
    <map-head>
    </map-head>
    <map-body>
    <map-feature>
    <#if attributes.LAND.value == "66.0">
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-multipolygon>
          <#list 0 ..< attribute.rawValue.getNumGeometries() as index>
            <#assign polygon = attribute.rawValue.getGeometryN(index)>
           <map-polygon>
           <#assign shell = polygon.getExteriorRing()><map-coordinates><#list shell.coordinates as coord><#if coord?index == 0><map-span class="desired">${coord.x} ${coord.y}<#elseif coord?index == 4> ${coord.x} ${coord.y}</map-span><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates>
          <#list 0 ..< polygon.getNumInteriorRing() as index>
            <#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord><#if coord?index == 0><map-span class="desired">${coord.x} ${coord.y} <#elseif coord?index == 4> ${coord.x} ${coord.y}</map-span><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates></#list>
           </map-polygon>
            </#list>
           </map-multipolygon>
          </map-geometry>
        </#if>
      </#list>
    <#else>
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-multipolygon>
          <#list 0 ..< attribute.rawValue.getNumGeometries() as index>
            <#assign polygon = attribute.rawValue.getGeometryN(index)>
           <map-polygon>
           <#assign shell = polygon.getExteriorRing()><map-coordinates><#list shell.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates>
          <#list 0 ..< polygon.getNumInteriorRing() as index>
            <#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates></#list>
           </map-polygon>
            </#list>
           </map-multipolygon>
          </map-geometry>
        </#if>
      </#list>
    </#if>
    </map-feature>
    </map-body>
    </mapml->

That template is looking for a particular polygon that has the attribute name "LAND" whose value is "66.0". I know this is a multipolygon, so should perhaps go through this branch. However, the response is as follows, I think showing that the attribute test is working, but there's a unmarshal error:

<?xml version="1.0" encoding="UTF-8"?><ServiceExceptionReport version="1.3.0" xmlns="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ogc http://localhost:8080/geoserver/schemas/wms/1.3.0/exceptions_1_3_0.xsd">   <ServiceException>
      org.geoserver.platform.ServiceException: javax.xml.bind.UnmarshalException
 - with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: com.ctc.wstx.exc.WstxParsingException: Unexpected close tag &lt;/map-coordinates&gt;; expected &lt;/map-span&gt;.
 at [row,col {unknown-source}]: [13,154]]
javax.xml.bind.UnmarshalException
 - with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: com.ctc.wstx.exc.WstxParsingException: Unexpected close tag &lt;/map-coordinates&gt;; expected &lt;/map-span&gt;.
 at [row,col {unknown-source}]: [13,154]]
Exception Description: An error occurred unmarshalling the document
Internal Exception: com.ctc.wstx.exc.WstxParsingException: Unexpected close tag &lt;/map-coordinates&gt;; expected &lt;/map-span&gt;.
 at [row,col {unknown-source}]: [13,154]
Unexpected close tag &lt;/map-coordinates&gt;; expected &lt;/map-span&gt;.
 at [row,col {unknown-source}]: [13,154]
</ServiceException></ServiceExceptionReport>

wdyt?

@turingtestfail
Copy link
Author

ok this may be progress, or maybe not.

I am trying to get the polygon / span template working on the nyc poly_landmarks layer working. I have this template so far, changed from your original example:

<mapml- xmlns="http://www.w3.org/1999/xhtml">
    <map-head>
    </map-head>
    <map-body>
    <map-feature>
    <#if attributes.LAND.value == "66.0">
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-multipolygon>
          <#list 0 ..< attribute.rawValue.getNumGeometries() as index>
            <#assign polygon = attribute.rawValue.getGeometryN(index)>
           <map-polygon>
           <#assign shell = polygon.getExteriorRing()><map-coordinates><#list shell.coordinates as coord><#if coord?index == 0><map-span class="desired">${coord.x} ${coord.y}<#elseif coord?index == 4> ${coord.x} ${coord.y}</map-span><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates>
          <#list 0 ..< polygon.getNumInteriorRing() as index>
            <#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord><#if coord?index == 0><map-span class="desired">${coord.x} ${coord.y} <#elseif coord?index == 4> ${coord.x} ${coord.y}</map-span><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates></#list>
           </map-polygon>
            </#list>
           </map-multipolygon>
          </map-geometry>
        </#if>
      </#list>
    <#else>
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-multipolygon>
          <#list 0 ..< attribute.rawValue.getNumGeometries() as index>
            <#assign polygon = attribute.rawValue.getGeometryN(index)>
           <map-polygon>
           <#assign shell = polygon.getExteriorRing()><map-coordinates><#list shell.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates>
          <#list 0 ..< polygon.getNumInteriorRing() as index>
            <#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates></#list>
           </map-polygon>
            </#list>
           </map-multipolygon>
          </map-geometry>
        </#if>
      </#list>
    </#if>
    </map-feature>
    </map-body>
    </mapml->

That template is looking for a particular polygon that has the attribute name "LAND" whose value is "66.0". I know this is a multipolygon, so should perhaps go through this branch. However, the response is as follows, I think showing that the attribute test is working, but there's a unmarshal error:

<?xml version="1.0" encoding="UTF-8"?><ServiceExceptionReport version="1.3.0" xmlns="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/ogc http://localhost:8080/geoserver/schemas/wms/1.3.0/exceptions_1_3_0.xsd">   <ServiceException>
      org.geoserver.platform.ServiceException: javax.xml.bind.UnmarshalException
 - with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: com.ctc.wstx.exc.WstxParsingException: Unexpected close tag &lt;/map-coordinates&gt;; expected &lt;/map-span&gt;.
 at [row,col {unknown-source}]: [13,154]]
javax.xml.bind.UnmarshalException
 - with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: com.ctc.wstx.exc.WstxParsingException: Unexpected close tag &lt;/map-coordinates&gt;; expected &lt;/map-span&gt;.
 at [row,col {unknown-source}]: [13,154]]
Exception Description: An error occurred unmarshalling the document
Internal Exception: com.ctc.wstx.exc.WstxParsingException: Unexpected close tag &lt;/map-coordinates&gt;; expected &lt;/map-span&gt;.
 at [row,col {unknown-source}]: [13,154]
Unexpected close tag &lt;/map-coordinates&gt;; expected &lt;/map-span&gt;.
 at [row,col {unknown-source}]: [13,154]
</ServiceException></ServiceExceptionReport>

wdyt?

In my version of the sample data, I was unable to find LAND=66.0, but I did find LAND=72.0. When I used the template you created with that value and the most current branch it worked for me when I tested with this URL:

http://localhost:8080/geoserver/tiger/wms?format_options=mapmlfeatures:true&request=GetMap&crs=MapML:WGS84&bbox=-74.30706024171461,40.703659057624364,-73.6478805542147,40.85746765137434&format=text/mapml&language=en&version=1.3.0&transparent=true&service=WMS&layers=poly_landmarks&width=1920&styles=poly_landmarks&height=448

Also, FYI I changed the error handling to return the full template output string as part of the error, so it should be a bit easier to debug things.

@prushforth
Copy link
Collaborator

I've been messing around with the template to process the outer polygon example:

<mapml- xmlns="http://www.w3.org/1999/xhtml">
    <map-head>
    </map-head>
    <map-body>
    <map-feature>
    <#if attributes.LANAME.value == "Central Park">
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-multipolygon>
          <#list 0 ..< attribute.rawValue.getNumGeometries() as index>
            <#assign polygon = attribute.rawValue.getGeometryN(index)>
           <map-polygon>
           <#assign shell = polygon.getExteriorRing()>
             <map-coordinates><#-- note that having spaces around coordinates is VITAL -->
               <map-span class="desired"><#list shell.coordinates as coord> ${coord.x} ${coord.y} </#list></map-span>
              </map-coordinates>
          <#list 0 ..< polygon.getNumInteriorRing() as index>
            <#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates></#list>
           </map-polygon>
            </#list>
           </map-multipolygon>
          </map-geometry>
        </#if>
      </#list>
    <#else>
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-multipolygon>
          <#list 0 ..< attribute.rawValue.getNumGeometries() as index>
            <#assign polygon = attribute.rawValue.getGeometryN(index)>
           <map-polygon>
           <#assign shell = polygon.getExteriorRing()><map-coordinates><#list shell.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates>
          <#list 0 ..< polygon.getNumInteriorRing() as index>
            <#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates></#list>
           </map-polygon>
            </#list>
           </map-multipolygon>
          </map-geometry>
        </#if>
      </#list>
    </#if>
    </map-feature>
    </map-body>
    </mapml->

I noticed that the ftl may not get a hold of the polygon when it contains a <map-span class="bbox">...</map-span>, for example when you zoom in on central park for the above template, the desired class is not rendered. Also, I noticed that the WFS setting for number of decimal places is disregarded (not sure if it's in all circumstances, but for sure when the ftl gets the polygon it forgets about decimal places).

Also, I wanted to try inserting a <map-a href> but I had to update the JAXB annotations to enable that. It worked, but then the client ran into problems processing the <map-a> for reasons unrelated to GeoServer (I think). Anyway, just to let you know that I'm still looking at this.

@turingtestfail
Copy link
Author

I've been messing around with the template to process the outer polygon example:

<mapml- xmlns="http://www.w3.org/1999/xhtml">
    <map-head>
    </map-head>
    <map-body>
    <map-feature>
    <#if attributes.LANAME.value == "Central Park">
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-multipolygon>
          <#list 0 ..< attribute.rawValue.getNumGeometries() as index>
            <#assign polygon = attribute.rawValue.getGeometryN(index)>
           <map-polygon>
           <#assign shell = polygon.getExteriorRing()>
             <map-coordinates><#-- note that having spaces around coordinates is VITAL -->
               <map-span class="desired"><#list shell.coordinates as coord> ${coord.x} ${coord.y} </#list></map-span>
              </map-coordinates>
          <#list 0 ..< polygon.getNumInteriorRing() as index>
            <#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates></#list>
           </map-polygon>
            </#list>
           </map-multipolygon>
          </map-geometry>
        </#if>
      </#list>
    <#else>
      <#list attributes as attribute>
        <#if attribute.isGeometry>
          <map-geometry>
            <map-multipolygon>
          <#list 0 ..< attribute.rawValue.getNumGeometries() as index>
            <#assign polygon = attribute.rawValue.getGeometryN(index)>
           <map-polygon>
           <#assign shell = polygon.getExteriorRing()><map-coordinates><#list shell.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates>
          <#list 0 ..< polygon.getNumInteriorRing() as index>
            <#assign hole = polygon.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord> ${coord.x} ${coord.y} </#list></map-coordinates></#list>
           </map-polygon>
            </#list>
           </map-multipolygon>
          </map-geometry>
        </#if>
      </#list>
    </#if>
    </map-feature>
    </map-body>
    </mapml->

I noticed that the ftl may not get a hold of the polygon when it contains a ..., for example when you zoom in on central park for the above template, the desired class is not rendered. Also, I noticed that the WFS setting for number of decimal places is disregarded (not sure if it's in all circumstances, but for sure when the ftl gets the polygon it forgets about decimal places).

Also, I wanted to try inserting a but I had to update the JAXB annotations to enable that. It worked, but then the client ran into problems processing the for reasons unrelated to GeoServer (I think). Anyway, just to let you know that I'm still looking at this.

Good catch on the number of decimals. The template is generating the coordinates directly, bypassing the existing formatting. The latest push corrects that by applying the formatting to the template output. With regards to the "bbox", that was a specific choice I made to skip the template insertion for features with the "bbox" class assigned. My thinking is that those geometries are specially reserved due to their presence on the periphery for tiling purposes? If that is not a correct interpretation, should I be merging the span classes to include both in those cases?

@prushforth
Copy link
Collaborator

prushforth commented Jul 18, 2024 via email

Copy link
Member

@aaime aaime left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a go at documentation and glanced over the code.
As a potential user of this, I really like the ability to customize links, HTML CSS, MapML CSS, and the feature attributes.

One thing that I think would be pretty interesting, is using the templates to push the styling beyond what the SLD translator can do. I'm not taking about the map-span here, but about templates that would create CSS for the features, and then perform logic, checks, on the feature attributes, and decide which CSS classes to apply a feature as a consequence.... it would be more powerful than SLD itself, full programmatic style control!
However, I'm not sure the implementation allows this use case, I see it grabbing the attributes and the geometry, but not the feature style.

At the same time, if one is going to use templates to do advanced, programmatic styling, having to re-encode also the attributes looks painful.

In general, dealing with geometries encoding is a lot of work... which is not surprising, it's already a lot of work to do GetFeaureInfo HTML templates, and all they do is to create a simple HTML table.... here we are at different level of complexity.

In terms of adding styles to clipped geometries... the clipping output of a polygon is normally stored in a geometry user data, but it's not a Polygon anymore, because the different sub-spans cannot be represented in JTS geometric anymore... they are a set of objects called TaggedPolygon, TaggedLineString and TaggedCoordinateSequence... I guess they could be used in a template too, but it would make the logic to build mapml even harder. Are we sure there are users willing to go there? Personally I already got lost in the polygon examples as they are...

<!-- End of added from the template -->
</head>

GetMap XML Head Stylesheet Templating
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the usage "XML", I'd call it MapML. MapML is a set of tag extensions to HTML, which can be also valid XML, when written as XHTML, but it's not always so.

Suggested change
GetMap XML Head Stylesheet Templating
GetMap MapML Head Stylesheet Templating

If you agree wit this change, please remove all other XML references as well.


GetMap XML Head Stylesheet Templating
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
MapML in XML format includes a map-head element that includes map-link elements to link to other resources, including map style variants. Additional map-link elements can be added to the map-head element by creating a mapml-head.ftl template in the GeoServer data directory in the directory for the layer we wish to append map-links to. For example we could create the mapml-head.ftl file under ``workspaces/tiger/nyc/poly_landmarks_shapefile/poly_landmarks``:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MapML in XML format includes a map-head element that includes map-link elements to link to other resources, including map style variants. Additional map-link elements can be added to the map-head element by creating a mapml-head.ftl template in the GeoServer data directory in the directory for the layer we wish to append map-links to. For example we could create the mapml-head.ftl file under ``workspaces/tiger/nyc/poly_landmarks_shapefile/poly_landmarks``:
MapML in XML format includes a map-head element that includes map-link elements to link to other resources, including map style variants. Additional map-link elements can be added to the map-head element by creating a ``mapml-head.ftl`` template in the GeoServer data directory in the directory for the layer we wish to append map-links to. For example we could create the ``mapml-head.ftl`` file under ``workspaces/tiger/nyc/poly_landmarks_shapefile/poly_landmarks``:

The template names should be formatted as code. Also, it would be nice to have a summary table showing the template file names and their general usage (rather than having to go and search ".ftl" in the page)

<map-geometry>
<map-point>
<map-coordinates><#list gattribute.rawValue.coordinates as coord>
<#if coord?index == 0><map-span class="desired">${coord.x} ${coord.y}</map-span><#else>${coord.x} ${coord.y}</#if></#list></map-coordinates></map-point>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a point as an example... coord?index can only be 0 or not? Mabe better to use a linestring?


This would result in a MapML feature output body that would resemble::

<mapml- xmlns="http://www.w3.org/1999/xhtml"><map-head><map-title>Bridges</map-title><map-meta charset="UTF-8"/><map-meta content="text/mapml" http-equiv="Content-Type"/><map-meta name="extent" content="top-left-longitude=-180.000000,top-left-latitude=90.000000,bottom-right-longitude=180.000000,bottom-right-latitude=-90.000000"/><map-meta name="cs" content="gcrs"/><map-meta name="projection" content="MapML:urn:ogc:def:crs:EPSG::4326"/><map-style>.bbox {display:none} .Bridges-r1-s1{r:48.0; stroke-opacity:1.0; stroke-dashoffset:0; well-known-name:square; stroke-width:1.0; opacity:1.0; fill:#808080; fill-opacity:1.0; stroke:#000000; stroke-linecap:butt}</map-style></map-head><map-body><map-feature id="Bridges.1107531599613" class="Bridges-r1-s1"><map-geometry><map-point><map-coordinates><map-span class="desired">0.0007 0.0002</map-span></map-coordinates></map-point></map-geometry><map-properties><table xmlns="http://www.w3.org/1999/xhtml"><thead><tr><th role="columnheader" scope="col">Property name</th><th role="columnheader" scope="col">Property value</th></tr></thead><tbody><tr><th scope="row">FID</th><td itemprop="FID">110</td></tr><tr><th scope="row">UPDATED NAME</th><td itemprop="NAME">CHANGED Cam Bridge</td></tr></tbody></table></map-properties></map-feature></map-body></mapml->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part should really be pretty-printed

<map-geometry>
<map-polygon>
<#assign shell = attribute.rawValue.getExteriorRing()><map-coordinates><#list shell.coordinates as coord><#if coord?index == 0><map-span class="desired">${coord.x} ${coord.y}<#elseif coord?index == 3> ${coord.x} ${coord.y}</map-span><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates>
<#list 0 ..< attribute.rawValue.getNumInteriorRing() as index>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<#list 0 ..< attribute.rawValue.getNumInteriorRing() as index>
<#list 0 ..< attribute.rawValue.getNumInteriorRing() as index>

This bit syntax is unfamiliar to me... is it actually working? Or was it meant to be

<#list 0 ..attribute.rawValue.getNumInteriorRing() as index>

<map-polygon>
<#assign shell = attribute.rawValue.getExteriorRing()><map-coordinates><#list shell.coordinates as coord><#if coord?index == 0><map-span class="desired">${coord.x} ${coord.y}<#elseif coord?index == 3> ${coord.x} ${coord.y}</map-span><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates>
<#list 0 ..< attribute.rawValue.getNumInteriorRing() as index>
<#assign hole = attribute.rawValue.getInteriorRingN(index)><map-coordinates><#list hole.coordinates as coord><#if coord?index == 0><map-span class="desired">${coord.x} ${coord.y} <#elseif coord?index == 3> ${coord.x} ${coord.y}</map-span><#else> ${coord.x} ${coord.y}</#if></#list></map-coordinates></#list>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite packed and nested... can it be unfolded a bit for readability, or the extra spaces would break parsing? Most of the examples seem to suffer from the same issue.
Since we are parsing it back, the generated XML does not need to be "pretty", as long as it's valid.

throws IOException {
if (mapMLStyles != null && mapMLStyles.isEmpty()) {
// no applicable styles, probably because of scale
return Optional.empty();
}
Feature f = new Feature();
f.setId(sf.getID());
Optional<Map<String, String>> replacmentAttsOptional =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Optional<Map<String, String>> replacmentAttsOptional =
Optional<Map<String, String>> replacementAttsOptional =


private static Optional<Map<String, String>> getTemplateAttributes(
Optional<Mapml> templateOptional) {
if (templateOptional.isPresent()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch, this method is not using the one thing I like most about Optional: avoiding deep nested checks over chained calls.

I've asked ChatGPT to simplify it so that it uses Otional's map and filter, I'm not sure it's correct, but it certainly looks as I would expect (more compact and I believe more readable too):

private static Optional<Map<String, String>> getTemplateAttributes(
        Optional<Mapml> templateOptional) {
    return templateOptional
        .map(Mapml::getBody)
        .map(Body::getFeatures)
        .filter(features -> features != null && !features.isEmpty())
        .map(features -> features.get(0))
        .map(Feature::getProperties)
        .map(Properties::getOtherAttributes)
        .filter(attributes -> attributes != null && !attributes.isEmpty() && attributes.values().size() % 2 == 0)
        .map(attributes -> {
            List<String> values = new ArrayList<>(attributes.values());
            return IntStream.range(0, values.size() / 2)
                .boxed()
                .collect(Collectors.toMap(i -> values.get(i * 2), i -> values.get(i * 2 + 1)));
        });
}

/** Collects the attributes representation as a HTML table */
private String collectAttributes(SimpleFeature sf) {
private String collectAttributes(
SimpleFeature sf, Optional<Map<String, String>> replacmentAttsOptional) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SimpleFeature sf, Optional<Map<String, String>> replacmentAttsOptional) {
SimpleFeature sf, Optional<Map<String, String>> replacementAttsOptional) {

@prushforth
Copy link
Collaborator

I'm not taking about the map-span here, but about templates that would create CSS for the features, and then perform logic, checks, on the feature attributes, and decide which CSS classes to apply a feature as a consequence.... it would be more powerful than SLD itself, full programmatic style control!

I think this sounds like a good direction. I am not knowledgeable enough about SLD to know where its limits are, but having the ability to encode procedural logic to derive class values sounds like what I would expect of the (ftl) templating system.

However, I'm not sure the implementation allows this use case, I see it grabbing the attributes and the geometry, but not the feature style.

If it's simple to achieve this, let's add it in. If not, let's skip it for now. Either way, we can then let the whole templating feature content MapML extension feature mature so that we can use it / play with it until we know exactly where we want to go with it, and then do that as future work.

I guess they could be used in a template too, but it would make the logic to build mapml even harder. Are we sure there are users willing to go there? Personally I already got lost in the polygon examples as they are...

Understood, this is why I'm working on making example ftl files that work with a specific data set that geoserver users have access to (the release data directory). I think if a user can take an example that she can see works on data set A, and apply it to data set Z that she owns, that is one way of getting users up to speed.

As previously discussed, it would be ideal (in the future) to be able to generate ftl files from the output of an interactive graphic environment such as from CSV encoding of a specific segment to hyperlink or style or otherwise mark up etc. Even a combination of generated and then manually edited ftl content could be interesting.

In terms of adding styles to clipped geometries... the clipping output of a polygon is normally stored in a geometry user data, but it's not a Polygon anymore, because the different sub-spans cannot be represented in JTS geometric anymore... they are a set of objects called TaggedPolygon, TaggedLineString and TaggedCoordinateSequence..

That's pretty cool actually!

. I guess they could be used in a template too, but it would make the logic to build mapml even harder. Are we sure there are users willing to go there?

To avoid having to mess with what the representation of the geometry (part) is (i.e. TaggedPolygon et al), we will need to be able to reliably wrap all the coordinates of the <map-coordinates> in a <map-span> (or <map-a>) regardless of whether there's internal structure or not. We might avoid having to use <map-span> to wrap whole geometry parts (but not be able to avoid <map-a>) by supporting the <map-coordinates class> (global) attribute. (Aside: I thought we already supported this on the client, but I tested it and it doesn't quite work yet.) In GeoServer, we would have to add the class attribute to the JAXB definition of Coordinates.java (pretty simple to do, I believe).

Personally I already got lost in the polygon examples as they are...

Pretty printing might help. Knowing / documenting the data model available, and how to manipulate it would help. Working examples of planned / supported use cases would help. But yes, if we don't have to go there (exposing TaggedPolygon et al to the ftl data model), I think it would be better to avoid it until we have found what users / we want to do with it.

@prushforth
Copy link
Collaborator

prushforth commented Jul 20, 2024

Thinking more about this. The geometry is never going to be consistent. Joe's approach of filtering out the tagged geometries was appropriate, but I think manipulating coordinates in the ftl is is bound to not work anyway because the geometry is mostly often going to be chopped up. However I would like to achieve wrapping the whole geometry, tagged or not, in a map-a, and potentially calculating a class value for it based on attributes. In short I think we can't expect to add links or spans to sub geometries because of panning and zooming making those geometries too unreliable.

@turingtestfail
Copy link
Author

However I would like to achieve wrapping the whole geometry, tagged or not, in a map-a, and potentially calculating a class value for it based on attributes.

I can make changes to the documentation examples to reflect this approach - using the FreeMarker template to wrap selected whole geometries in map-a tags.

How would you envision the mapping of the class values from the attributes? Would it be logic in the FTL using "if-else" tags to specify a "map-a" tag in with "class='foo'" in place and "class='bar'" in another?

@prushforth
Copy link
Collaborator

prushforth commented Jul 20, 2024

How would you envision the mapping of the class values from the attributes?

I think, because the state of the geometry internally depends on whether or not it is clipped by the viewport or tile, that we will have to be able to have / target a class attribute on the actual map-geometry element. I'm pretty sure this will work in the client, and if it doesn't currently (I will verify), I will make it work. IIRC, we had an issue with that when making SLD rules apply, so we put the class attribute onto map-feature. So, it would be ideal to be able to merge a ftl-calculated class value into any existing values (on map-feature), or to put the new value into a new class attribute on the map-geometry.

I know that wrapping a map-geometry in a map-a will work, because we have examples of that working here for example.

Edit: Here's how the linked example of <map-a> works, which is by wrapping the content of the <map-geometry> in a <map-a>:

<map-geometry>
  <map-a href="#11,-123.362105,48.430882">
    <map-point>
      <map-coordinates>-123.362105 48.430882</map-coordinates>
    </map-point>
  </map-a>
</map-geometry>

As for how to template the tagged geometries, we'll have to think on that. It would be nice to have but not a show stopper, and we don't want to make it so complicated that it's a barrier.

@turingtestfail
Copy link
Author

<map-a href="#11,-123.362105,48.430882">

Peter - I have added the "map-a" wrapper to the JaxB definitions in the most recent push to this PR and tried the approach you described but I the javascript associated with the preview viewer doesn't seem to be able to handle it? See below for the template I used with the NYC TIGER POI sample dataset:





<#list attributes as attribute>
<#if attribute.name == "NAME">

<#else>

</#if>
</#list>
<#list attributes as gattribute>
<#if gattribute.isGeometry>
<#if attributes.NAME.value == "museam"></#if><#list gattribute.rawValue.coordinates as coord>${coord.x} ${coord.y}</#list><#if attributes.NAME.value == "museam"></#if>
</#if>
</#list>


@turingtestfail
Copy link
Author

<map-a href="#11,-123.362105,48.430882">

Peter - I have added the "map-a" wrapper to the JaxB definitions in the most recent push to this PR and tried the approach you described but I the javascript associated with the preview viewer doesn't seem to be able to handle it? See below for the template I used with the NYC TIGER POI sample dataset: <#list attributes as attribute> <#if attribute.name == "NAME"> <#else> </#if> </#list> <#list attributes as gattribute> <#if gattribute.isGeometry> <#if attributes.NAME.value == "museam"></#if><#list gattribute.rawValue.coordinates as coord>${coord.x} ${coord.y}</#list><#if attributes.NAME.value == "museam"></#if> </#if> </#list>

@prushforth Should I continue forward with documenting (and unit tests) that demonstrate the map-a wrapper approach? Is there a new version of the JavaScript client that supports map-a? Thanks.

@turingtestfail
Copy link
Author

turingtestfail commented Jul 31, 2024

@prushforth Here is the template I used (the one in the example above did not copy correctly):

<mapml- xmlns="http://www.w3.org/1999/xhtml">
   <map-head>
   </map-head>
   <map-body>
     <map-feature>
       <#list attributes as attribute>
         <#if attribute.name == "NAME">
           <map-properties name="UPDATED ${attribute.name}" value="CHANGED ${attribute.value}"/>
         <#else>
           <map-properties name="${attribute.name}" value="${attribute.value}"/>
         </#if>
       </#list>
       <#list attributes as gattribute>
         <#if gattribute.isGeometry>
           <map-geometry><#if attributes.NAME.value == "museam"><map-a href="#DESIRED,-74.01046109936,40.70758762626"></#if><map-point><map-coordinates><#list gattribute.rawValue.coordinates as coord>${coord.x} ${coord.y}</#list></map-coordinates></map-point><#if attributes.NAME.value == "museam"></map-a></#if></map-geometry>
          </#if>
        </#list>
       </map-feature>
     </map-body>
     </mapml->

@prushforth
Copy link
Collaborator

Hi Joe, sorry for not replying earlier. I had this on my list to look at today, and will proceed with that plan now. Thanks for your patience.

@prushforth
Copy link
Collaborator

@turingtestfail Joe I'm having difficulty building and running this branch now - could you make it so that I can just clone it and build it? I have to merge main and I'm not sure how to resolve the conflicts I'm getting.

@prushforth
Copy link
Collaborator

prushforth commented Jul 31, 2024

Specifically, while I can successfully build this branch, I can't deploy it, as GeoServer fails on startup with the following message:

31 Jul 14:00:33 ERROR  [context.ContextLoader] - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gMLPreview' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-web-demo-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'geoServer' while setting bean property 'geoserver'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'geoServer' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'catalog' while setting bean property 'catalog'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'localWorkspaceCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'advertisedCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'advertisedCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Cannot resolve reference to bean 'secureCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'accessRulesDao' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationSecurityContext.xml]: Cannot resolve reference to bean 'rawCatalog' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'rawCatalog' defined in URL [jar:file:/home/prushforth/catalina/nb1/webapps/geoserver/WEB-INF/lib/gs-main-2.26-SNAPSHOT.jar!/applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.NoSuchFieldError: QUETTA
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)

Earlier, I successfully got around that by merging main into this branch, but now I get conflicts and I am not able to resolve them. At least, not yet.

@prushforth
Copy link
Collaborator

prushforth commented Jul 31, 2024

I have been able to get the server running using this process:

Step 1: From your project repository, check out a new branch and test the changes.

git checkout -b turingtestfail-GEOS-11368-MapML-FreeMarker main
git pull https://github.com/turingtestfail/geoserver.git GEOS-11368-MapML-FreeMarker

+/- some fudging with stuff.

I confirm that there's a bug in the viewer code that prevents <map-a> from working with features loaded via <map-link rel=features>, and I'm working on that now. I think we can proceed in this direction anyway, and I will try to fix the bug.

@aaime
Copy link
Member

aaime commented Aug 1, 2024

@prushforth so we are good for a public PR?

@prushforth
Copy link
Collaborator

Yes

@turingtestfail turingtestfail force-pushed the GEOS-11368-MapML-FreeMarker branch 2 times, most recently from d31c0cc to a5a1c5c Compare August 2, 2024 07:15
started on template page

ftl file names correction

fixed xml code block and added map-property

Created preview header integration test and started extracting template

swapped in better method for empty feature

finished first integration test

switched to dedicated template

head template style

registering servicelink

fixed servicelink

changed serviceLink to base,path,kvp

cleanup

dollar signs breaking code block

started on subfeature span insertion with integration test

Got point xml interpolation working

progressing on polygon

Got polygon unmarshal working

got multipolygon to unmarshal

changed strings to coords and linestring parsing

removed interpolated, created head styles using basic mapml

attributes and point test working and phantom space removed

polygon and multipolygon tests

added feature id check to multipolygon test

tests with space replacement

version that uses lists of coordinates instead of strings

removed some other remainder stuff from the space thing

cleanup

added check for tagged geom

doc update

PR changes, mainly map-span

tests updated without xml escape

updated documentation removing cdata escaping

added template attributes to mapml feature

fixed attribute replacement and added documentation examples

more doc update

line test fix

fixed issue with geometrycollection and updated documentation with example

better output if error

format coordinates, including number of decimals

fixed pmd

PR doc updates and started on a wrapper

fixed underline in template doc

preview header change restored

test

remoe ipr iws

simplified optional

doc updates
@turingtestfail turingtestfail force-pushed the GEOS-11368-MapML-FreeMarker branch from 8911220 to 8d7d7b6 Compare August 2, 2024 08:18
@aaime aaime closed this Dec 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants