Skip to content

GSIP 204

Kevin Smith edited this page Sep 14, 2021 · 10 revisions

GSIP 204 - Mark Factories pre-process rendering hint

Overview

Proposed By

Fernando Mino

Assigned to Release

This proposal is for GeoServer 2.21-beta, 2.20.1, 2.19.3.

State

  • Under Discussion
  • In Progress
  • Completed
  • Rejected
  • Deferred

Motivation

We found on some deployments GeoServer WKT evaluation starts with SVG instead GeoTools core ones.

Tomcat 8+ class loading order changed

From https://www.xspdf.com/resolution/50039947.html Order of loading jar files from lib directory, Like many of the issues that trouble new Tomcat users, this problem is usually quite easy WEB-INF/classes and WEB-INF/lib, respectively and in that order. In previous versions of Tomcat, the classloader hierarchy worked a little differently. A classloader for Apache Tomcat 8 which loads the jars of WEB-INF lib in alphabetical order. Prior to version 8, Apache Tomcat loaded the jars of the WEB-INF lib directory in alphabetical order. Starting with version 8, the order is not predictable anymore and can lead to erratic behaviors, especially when deploying applications in a clustered environment.

Due to tomcat 8+ random class loading order, on some environments we have for every feature the SVGMarkFactory is tried to execute before the Geotools core ones: SVGMarkFactory.getShape(Graphics2D, Expression, Feature)

Take into account the issue randomly happens by tomcat installation/deployment basis. That's why sometimes it happens after a redeployment.

The SVG check is slow.

We did a performance improvement before for URL converter code, but anyway SVG WKT parsing check and exception handling is expensive for lots of features in the rendering phase. We don't have, currently, a way to handle the factories order or execution allow rules in GeoServer. That's why we are proposing this configuration enhacement.

Proposal

GeoTools Rendering hint.

This is on discussion stage at GeoTools community.

GeoTools Rendering Hints processor.

Update DynamicSymbolFactoryFinder with the missing getMarkFactories( Hints ) method (one already existed for getExternalGraphicFactories(Hints) and provide hints for both sorting and filtering.

class DynamicSymbolFactoryFinder {
  
  public static final Hints.Key MARK_FACTORY_ORDER = new Hints.Key(Comparator.class);
  public static final Hints.Key MARK_FACTORY_FILTER = new Hints.Key(Predicate.class);

  Iterator<MarkFactory> getMarkFactories()
  Iterator<MarkFactory> getMarkFactories( Hints )
  Iterator<ExternalGraphicFactory> getExternalGraphicFactories()
  Iterator<ExternalGraphicFactory> getExternalGraphicFactories(Hints hints)
}

The SLDStyleFactory change is minimal. The getIcon(ExternalGraphic eg, Object feature, double size) method already shows how to use hints to control factory lookup:

        // scan the external graphic factories and see which one can be used
        Iterator<ExternalGraphicFactory> it =
                DynamicSymbolFactoryFinder.getExternalGraphicFactories(new Hints(renderingHints));

Applying the same approach to getShape(Mark mark, Object feature):

    private Shape getShape(Mark mark, Object feature) {
        ....   
        Iterator<MarkFactory> it = DynamicSymbolFactoryFinder.getMarkFactories(new Hints(renderingHints));
        while (it.hasNext()) {
            MarkFactory factory = it.next();
            ...
        }
        ... 
    }

For this to work DynamicSymbolFactoryFinder must respect the provided hints:

    public static synchronized Iterator<MarkFactory> getMarkFactories() {
        return getServiceRegistry().getFactories(MarkFactory.class, null, null).iterator();
    }
    public static synchronized Iterator<MarkFactory> getMarkFactories( Hints hints ) {
        Comparator sort = hints != null ? hints.get(MARK_FACTORY_ORDER) : null;
        Predicate filter = hints != null ? hints.get(MARK_FACTORY_FILTER) : null;

        getServiceRegistry().getFactories(MarkFactory.class, filter, hints);
        
        return sort != null ? factories.sorted(sort).iterator() : factories:iterator();
    }

GeoServer implementation

GeoServer will implement MarkFactoryProcessorProvider and pass this hint into the StreamingRenderer rendering hints map on every GetMap request. Also GeoServer will cache the per-feature-namespace result during the current rendering task in progress for performance optimization. This Mark Factories order configuration will be stored on the workspace-level WMS settings. The UI component to handle it (the include-exclude list panels) will work in the WMS main configuration page, allowing to store the per-workspace configuration.

Mark factories selection UI component example:

Backwards Compatibility

This extension will maintain backward compatibility with previous versions GeoServer setups, since if no custom configuration is found, the mark factories will be returned as found.

Feedback

Voting

Project Steering Committee:

  • Alessio Fabiani:
  • Andrea Aime: +1
  • Ian Turton: +1
  • Jody Garnett: +1
  • Jukka Rahkonen: +0
  • Kevin Smith: +1
  • Simone Giannecchini: +0
  • Torben Barsballe: +1
  • Nuno Oliveira: +1

Links

Clone this wiki locally