Skip to content

Instantly share code, notes, and snippets.

@emxsys
Last active August 22, 2023 10:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save emxsys/93c151c5ac6881199c25216c438e738e to your computer and use it in GitHub Desktop.
Save emxsys/93c151c5ac6881199c25216c438e738e to your computer and use it in GitHub Desktop.
How to setup a NASA feature server for place names

How to setup a NASA WorldWind feature server (WFS)

Ubuntu 18.04.4 LTS Initial Setup

Change root password

Changing password for root.
(current) UNIX password: 
Enter new UNIX password: 
Retype new UNIX password: 

Add new user and set password

adduser xxx
chgpasswd 

Update the firewall

 $ ufw app list
Available applications:
  OpenSSH

$ sudo ufw allow OpenSSH
Rules update
Rules updated (v6)

$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
OpenSSH (v6)               ALLOW       Anywhere (v6)             

Install Tomcat Application Server

Install Java (for Tomcat and GeoServer)

sudo apt-get update
sudo apt-get install default-jdk

Install Tomcat

  • Create a tomcat group
  • Create a tomcat user
  • Download a Tomcat distribution to /tmp
  • Extract the distribution to /opt/tomcat
  • Adjust the permissions of /opt/tomcat

See: https://www.digitalocean.com/community/tutorials/install-tomcat-9-ubuntu-1804

sudo groupadd tomcat
sudo useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat

cd /tmp
curl -O http://www-us.apache.org/dist/tomcat/tomcat-9/v9.0.17/bin/apache-tomcat-9.0.17.tar.gz
sudo mkdir /opt/tomcat
sudo tar xzvf apache-tomcat-9*tar.gz -C /opt/tomcat --strip-components=1

cd /opt/tomcat/
/opt/tomcat$ sudo chgrp -R tomcat /opt/tomcat
/opt/tomcat$ sudo chmod -R g+r conf
/opt/tomcat$ sudo chmod g+x conf
/opt/tomcat$ sudo chown  -R tomcat webapps/ work/ temp/ logs

Update Tomcat service

  • Get location of JAVA
  • Create tomcat.service file
  • Update service JAVA_HOME with JAVA location
  • Start Tomcat
  • Enable Tomcat service at startup

Get the path to Java

sudo update-java-alternatives -l

Example output

java-1.11.0-openjdk-amd64      1101       /usr/lib/jvm/java-1.11.0-openjdk-amd64
sudo nano /etc/systemd/system/tomcat.service

Paste the following into the tomcat.service file and edit the JAVA_HOME path:

[Unit]
Description=Apache Tomcat Web Application Container
After=network.target

[Service]
Type=forking

Environment=JAVA_HOME=/usr/lib/jvm/java-1.11.0-openjdk-amd64
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
Environment='CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC'
Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'

ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh

User=tomcat
Group=tomcat
UMask=0007
RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

Reload the service, start and enable the service.

sudo systemctl daemon-reload
sudo systemctl start tomcat
sudo systemctl status tomcat
sudo systemctl enable tomcat

Configure firewall to allow port 8080 (Tomcat)

$ sudo ufw allow 8080
Rule added
Rule added (v6)

Configure Tomcat users

$ sudo nano /opt/tomcat/webapps/host-manager/META-INF/context.xml
$ sudo nano /opt/tomcat/conf/tomcat-users.xml
$ sudo systemctl restart tomcat
$ sudo systemctl status tomcat

tomcat.users

<tomcat-users . . .>
    <user username="admin" password="password" roles="manager-gui,admin-gui"/>
</tomcat-users>

Allow manager app to be run by remote systems

  • Edit context.xml
  • Comment out default allow=ip-address or add remote ip address
sudo nano /opt/tomcat/webapps/manager/META-INF/context.xml

context.xml

<Context antiResourceLocking="false" privileged="true" >
  <!--
  <Valve className="org.apache.catalina.valves.RemoteAddrValve"
         allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
  -->
  <Manager sessionAttributeValueClassNameFilter="java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?$
</Context>

Apache Web Server

Install Apache

sudo apt-get update
sudo apt-get install apache2

Setting ServerName

Add the server name to the configuration to avoid nuisance errors from apache2ctl.

sudo nano /etc/apache2/apache2.conf 

For example, setting the server name to "worldwind22"

...
ServerName "worldwind22"
...

Validate the change and restart.

sudo apache2ctl configtest
sudo systemctl restart apache2

Test http://localhost (or https://localhost) in your browser and validate the Apache2 default page is displayed.

Adjust the firewall to allow web traffic

sudo ufw app list
sudo ufw app info "Apache Full"
sudo ufw allow in "Apache Full"

Install Let's Encrypt

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-apache

Setup the SSL certificate

sudo certbot --apache -d emxsys.net
sudo certbot renew --dry-run

Install Apache module for reverse proxy for Tomcat

See: https://www.digitalocean.com/community/tutorials/how-to-encrypt-tomcat-8-connections-with-apache-or-nginx-on-ubuntu-16-04

sudo apt-get update
sudo apt-get install libapache2-mod-jk
sudo nano /etc/libapache2-mod-jk/workers.properties 

/etc/libapache2-mod-jk/workers.properties

...
workers.tomcat_home=/opt/tomcat
...

Adjust Apache virtual host to proxy with mod_jk

Edit your Apache site configuration file(s) and add the 'JKMount' directive.

sudo apache2ctl -S
sudo nano /etc/apache2/sites-available/000-default.conf 

Example: 000-default.conf

<VirtualHost *:80>
    . . .
    JKMount /* ajp13_worker
    . . .
</VirtualHost>

Restart Apache and then test http://localhost (or https://localhost) in your browser and validate the Tomcat home page is displayed.

sudo systemctl restart apache2

Adding CORS support: Header set Access-Control-Allow-Origin "*"

Edit your Apache configuration file(s) and add the Access-Control-Allow-Origin header

sudo nano /etc/apache2/sites-available/000-default-le-ssl.conf 
sudo nano /etc/apache2/sites-available/000-default.conf 

Example

<VirtualHost *:80>
    . . .
    Header set Access-Control-Allow-Origin "*"
    . . .
</VirtualHost>

Validate and restart.

sudo apache2ctl configtest
sudo systemctl restart apache2

Enable Apache modules

Enable the specified modules and restart Apache

sudo a2enmod headers
sudo a2enmod rewrite
sudo a2enmod deflate
sudo systemctl restart apache2
sudo systemctl status apache2

Setup GeoServer

Download GeoServer

Visit the GeoServer (https://geoserver.org site and get the direct download link to the war servlet download for the latest release. Use this link to download the file with curl or simply download interactively via your browser.

cd \tmp
curl -O https://downloads.sourceforge.net/project/geoserver/GeoServer/2.15.0/geoserver-2.15.0-war.zip?r=https%3A%2F%2Fsourceforge.net%2Fprojects%2Fgeoserver%2Ffiles%2FGeoServer%2F2.15.0%2Fgeoserver-2.15.0-war.zip%2Fdownload

Install GeoServer using the Tomcat Manager

  1. Extract the geoserver.war file from the downloaded release.
  2. Edit the webapps/manager/WEB-INF/web.xml to allow large .war files to be deployed. Otherwise the following error may occur: manager.log snippet
FAIL - Deploy Upload Failed, Exception: [org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (102931473) exceeds the configured maximum (52428800)]

The original webapps/manager/WEB-INF/web.xml is constraned to 50MB

  <servlet>
    <servlet-name>HTMLManager</servlet-name>
    ...
    <multipart-config>
      <!-- 50MB max -->
      <max-file-size>52428800</max-file-size>
      <max-request-size>52428800</max-request-size>
      <file-size-threshold>0</file-size-threshold>
    </multipart-config>
  </servlet>

This webapps/manager/WEB-INF/web.xml snippet is large enough for geoserver.war

  <servlet>
    <servlet-name>HTMLManager</servlet-name>
    ...
    <multipart-config>
      <!-- 120MB max -->
      <max-file-size>1200000000</max-file-size>
      <max-request-size>1200000000</max-request-size>
      <file-size-threshold>0</file-size-threshold>
    </multipart-config>
  </servlet>
  1. Using a browser, access your Tomcat server's home page and log in to the Manager app.
    • Deploy the geoserver.war file

Configure GeoServer

  1. Change the admin password!

Setup PostGIS

See: https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-postgis-on-ubuntu-14-04

sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable
sudo apt-get update

sudo apt-get install postgis

Success. You can now start the database server using:

/usr/lib/postgresql/10/bin/pg_ctl -D /var/lib/postgresql/10/main -l logfile start

The installation procedure created a user account called postgres that is associated with the default Postgres role. In order to use Postgres, we'll need to log into that account. You can do that by typing:

sudo -i -u postgres

Restore databases

1. Create the geonames and places PostGIS databases using psql.

First login as the postgres user.

sudo -i -u postgres

Now create the databases using psql with the PostGIS extension, as follows:

postgres:~$ psql
psql (10.6 (Ubuntu 10.6-0ubuntu0.18.04.1))
Type "help" for help.

Create the databases:

postgres=# create database geonames;
CREATE DATABASE
postgres=# create database places;
CREATE DATABASE 

Add the PostGIS extensions:

postgres=# \c geonames;
You are now connected to database "geonames" as user "postgres".
geonames=# create extension postgis;
CREATE EXTENSION
geonames=# \c places
You are now connected to database "places" as user "postgres".
places=# create extension postgis;
CREATE EXTENSION

Quite psql

places=# **\q**

2. Now we will restore the databases using `pg_restore'

We will restore the databases from a previous backup created with pg_dump. Numerous errors will be reported as the backups were created with earlier version of Postgres.

pg_restore -d places ww22dumpplaces 
pg_restore -d geonames  ww22dumpgeonames 

Validate the databases by comparing the content below with your \dt describe table output.

postgres=# \c geonames
You are now connected to database "geonames" as user "postgres".

geonames=# \dt
              List of relations
 Schema |      Name       | Type  |  Owner
--------+-----------------+-------+----------
 public | citiesover100k  | table | postgres
 public | citiesover10k   | table | postgres
 public | citiesover15k   | table | postgres
 public | citiesover1k    | table | postgres
 public | citiesover500k  | table | postgres
 public | citiesover50k   | table | postgres
 public | spatial_ref_sys | table | postgres
(7 rows)

geonames=# \c places
You are now connected to database "places" as user "postgres".

places=# \dt
                  List of relations
 Schema |           Name           | Type  |  Owner
--------+--------------------------+-------+----------
 public | cia                      | table | postgres
 public | cia2                     | table | postgres
 public | countries                | table | postgres
 public | geonet_20060905          | table | postgres
 public | geonet_20060905_adm1     | table | postgres
 public | geonet_20060905_adm2     | table | postgres
 public | geonet_20060905_capitals | table | postgres
 public | geonet_20060905_oceans   | table | postgres
 public | geonet_20060905_ppl      | table | postgres
 public | geonet_20060905_ppla     | table | postgres
 public | spatial_ref_sys          | table | postgres
 public | us_counties              | table | postgres
 public | wpl_continents           | table | postgres
 public | wpl_countries            | table | postgres
 public | wpl_desertsplains        | table | postgres
 public | wpl_geonet_a_adm1        | table | postgres
 public | wpl_geonet_a_adm2        | table | postgres
 public | wpl_geonet_a_adm3        | table | postgres
 public | wpl_geonet_p_ppl         | table | postgres
 public | wpl_geonet_p_ppla        | table | postgres
 public | wpl_geonet_p_pplc        | table | postgres
 public | wpl_lakesrivers          | table | postgres
 public | wpl_mountainsvalleys     | table | postgres
 public | wpl_oceans               | table | postgres
 public | wpl_trenchesridges       | table | postgres
 public | wpl_us_anthropogenic     | table | postgres
 public | wpl_us_terrain           | table | postgres
 public | wpl_us_water             | table | postgres
 public | wpl_uscities0            | table | postgres
 public | wpl_uscitiesover0        | table | postgres
 public | wpl_uscitiesover100k     | table | postgres
 public | wpl_uscitiesover10k      | table | postgres
 public | wpl_uscitiesover1k       | table | postgres
 public | wpl_uscitiesover500k     | table | postgres
 public | wpl_uscitiesover50k      | table | postgres
 public | wpl_waterbodies          | table | postgres
(36 rows)

places=#

Create users

You will need to create a database user for GeoServer to connect to Postgres. Using psql we create a user named "geoserver" with a password of your choosing. You will use this user/password combination in GeoServer when connecting to the Posgres databases.

First login as the postgres user.

sudo -i -u postgres

Now create the user and grant priviledges to the databases:

psql

postgres=# create user geoserver WITH PASSWORD 'password-string';

postgres=# \c geonames
You are now connected to database "geonames" as user "postgres".

geonames=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to geoserver;
GRANT

geonames=# \c places
You are now connected to database "places" as user "postgres".

places=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public to geoserver;
GRANT

places=# \q

Configure GeoServer Features

1. Login to GeoServer

2. Create Stores for geonames and places

Repeat these steps for both the geonames and places databases.

  1. Select Stores > Add New Store
  2. Select PostGIS - PostGIS Database, and use the defaults except for the following:
    • Workspace: topp
    • Data Source Name: enter the database name
    • database: enter the database name
    • user: geoserver user created earlier
    • passwd: geoserver password created earlier
  3. Select Save

3. Create Styles used for Country Boundaries

Create a style called countryboundaries without a namespaceL

  1. Select Styles > Add New Style
  2. Uses the defaults except for the following:
    • Workspace: leave blank
    • Name: countryboundaries
    • Style Content:
<?xml version="1.0" encoding="ISO-8859-1"?>
<StyledLayerDescriptor version="1.0.0" 
    xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd" 
    xmlns="http://www.opengis.net/sld" 
    xmlns:ogc="http://www.opengis.net/ogc" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <!-- a named layer is the basic building block of an sld document -->

  <NamedLayer>
    <Name>Country Boundaries</Name>
    <UserStyle>
        <!-- they have names, titles and abstracts -->
      
      <Title>A boring default style</Title>
      <Abstract>A sample style that just prints out a transparent interior with a red outline</Abstract>


      <FeatureTypeStyle>
        <!--FeatureTypeName>Feature</FeatureTypeName-->
        <Rule>
          <Name>Rule 1</Name>
          <Title>Yellow Outline</Title>
          <Abstract>yellow outline 2 pixels wide</Abstract>

          <!-- like a linesymbolizer but with a fill too -->
          <PolygonSymbolizer>
            <Stroke>
              <CssParameter name="stroke">#FFFF00</CssParameter>
              <CssParameter name="stroke-width">2</CssParameter>
            </Stroke>
          </PolygonSymbolizer>
        </Rule>

        </FeatureTypeStyle>
    </UserStyle>
  </NamedLayer>
</StyledLayerDescriptor>
  1. Select Validate and then Submit

4. Create Layers for geonames

Repeat the following steps for these geonames tables

  • citiesover100k
  • citiesover10k
  • citiesover15k
  • citiesover1k
  • citiesover500k
  • citiesover50k
  1. Select Layers > Add new layer
  2. Add a layer from: topp:geonames
  3. Click Publish for one of the aforementioned layers
  4. In the Edit Layer screen, use the defaults except for the following:
    • Native Bounding Box: Compute from data
    • Lat/Lon Bounding Box: Compute from native bounds
    • Publishing tab > Default Style: capitals
  5. Click Save

5. Create Layers for places

Repeat the following steps for these places tables

  • cia
  • countries
  • wpl_continents
  • wpl_countries
  • wpl_desertsplains
  • wpl_geonet_a_adm1
  • wpl_geonet_a_adm2
  • wpl_geonet_p_ppl
  • wpl_geonet_p_ppla
  • wpl_geonet_p_pplc
  • wpl_lakesrivers
  • wpl_mountainsvalleys
  • wpl_oceans
  • wpl_trenchesridges
  • wpl_us_anthropogenic
  • wpl_us_terrain
  • wpl_us_water
  • wpl_uscities0
  • wpl_waterbodies
  1. Select Layers > Add new layer
  2. Add a layer from: topp:places
  3. Click Publish for one of the aforementioned layers
  4. In the Edit Layer screen, use the defaults except for the following:
    • Native Bounding Box: Compute from data
    • Lat/Lon Bounding Box: Compute from native bounds
    • Publishing tab > Default Style: for the cia layer select countryboundaries, for all others select capitals
  5. Click Save

Enable GML2-GZIP Support

The Java client makes GetFeature requests using an 'outputformat=GML2-GZiP` parameter. But contemporary version of GeoServer do not support GML2-GZIP. This issue can be mitigated in Apache by the following steps:

  • Rewriting the query string to replace GML2-GZIP with GML2 to satisfy GeoServer
  • Adding an Accept-Encoding "gzip" header to the request
  • Adding gzip compression to XML (GML) responses using a DEFLATE filter

This Apache configuration snippet demonstrates how to provide GML2-GZIP support:

	AddOutputFilterByType DEFLATE text/xml

	RequestHeader set Accept-Encoding "gzip"
 
	RewriteEngine on
	RewriteCond %{QUERY_STRING} ^(.*)GML2-GZIP(.*)$
	RewriteRule /geoserver/wfs /geoserver/wfs?%1GML2%2

Reference

Java NASAWFSPlaceNameLayer

public class NASAWFSPlaceNameLayer extends PlaceNameLayer {

    //String constants for name sets
    public static final String OCEANS="topp:wpl_oceans";
    public static final String CONTINENTS="topp:wpl_continents";
    public static final String WATERBODIES="topp:wpl_waterbodies";
    public static final String TRENCHESRIDGES="topp:wpl_trenchesridges";
    public static final String DESERTSPLAINS="topp:wpl_desertsplains";
    public static final String LAKESRIVERS="topp:wpl_lakesrivers";
    public static final String MOUNTAINSVALLEYS="topp:wpl_mountainsvalleys";
    public static final String COUNTRIES="topp:wpl_countries";
    public static final String GEONET_P_PPC="topp:wpl_geonet_p_pplc";
    public static final String CITIESOVER500K="topp:citiesover500k";
    public static final String CITIESOVER100K="topp:citiesover100k";
    public static final String CITIESOVER50K="topp:citiesover50k";
    public static final String CITIESOVER10K="topp:citiesover10k";
    public static final String CITIESOVER1K="topp:citiesover1k";
    public static final String USCITIESOVER0="topp:wpl_uscitiesover0";
    public static final String USCITIES0="topp:wpl_uscities0";
    public static final String US_ANTHROPOGENIC="topp:wpl_us_anthropogenic";
    public static final String US_WATER="topp:wpl_us_water";
    public static final String US_TERRAIN="topp:wpl_us_terrain";
    public static final String GEONET_A_ADM1="topp:wpl_geonet_a_adm1";
    public static final String GEONET_A_ADM2="topp:wpl_geonet_a_adm2";
    public static final String GEONET_P_PPLA="topp:wpl_geonet_p_ppla";
    public static final String GEONET_P_PPL="topp:wpl_geonet_p_ppl";
    public static final String GEONET_P_PPLC="topp:wpl_geonet_p_pplC";


    private static final String[] allNameSets={OCEANS, CONTINENTS, WATERBODIES, TRENCHESRIDGES, DESERTSPLAINS, LAKESRIVERS,
                                    MOUNTAINSVALLEYS, COUNTRIES, GEONET_P_PPC, CITIESOVER500K, CITIESOVER100K,
                                    CITIESOVER50K, CITIESOVER10K, CITIESOVER1K, USCITIESOVER0,USCITIES0,
                                    US_ANTHROPOGENIC, US_WATER, US_TERRAIN, GEONET_A_ADM1, GEONET_A_ADM2,
                                    GEONET_P_PPLA, GEONET_P_PPL};

    private static List activeNamesList = Arrays.asList(allNameSets);
    
    public NASAWFSPlaceNameLayer() {
        super(makePlaceNameServiceSet());
    }

    public void setPlaceNameSetsVisible(List names)
    {
        activeNamesList=names;
        makePlaceNameServiceSet();
    }

    private static PlaceNameServiceSet makePlaceNameServiceSet() {
        final String service = "https://worldwind22.arc.nasa.gov/geoserver/wfs";
        final String fileCachePath = "Earth/PlaceNames/WFSPlaceNamesVersion1.0";
        PlaceNameServiceSet placeNameServiceSet = new PlaceNameServiceSet();
        placeNameServiceSet.setExpiryTime(new GregorianCalendar(2008, 1, 11).getTimeInMillis());
        PlaceNameService placeNameService;
        final boolean addVersionTag=true;  //true if pointing to a new wfs server
        // Oceans
        if (activeNamesList.contains(OCEANS)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_oceans", fileCachePath, Sector.FULL_SPHERE, GRID_1x1,
                    java.awt.Font.decode("Arial-BOLDITALIC-12"), addVersionTag);
            placeNameService.setColor(new java.awt.Color(200, 200, 200));
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_A);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // Continents
        if (activeNamesList.contains(CONTINENTS)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_continents", fileCachePath, Sector.FULL_SPHERE,
                    GRID_1x1, java.awt.Font.decode("Arial-BOLD-12"), addVersionTag);
            placeNameService.setColor(new java.awt.Color(255, 255, 240));
            placeNameService.setMinDisplayDistance(LEVEL_G);
            placeNameService.setMaxDisplayDistance(LEVEL_A);
            placeNameServiceSet.addService(placeNameService, false);
        }

         // Water Bodies
        if (activeNamesList.contains(WATERBODIES)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_waterbodies", fileCachePath, Sector.FULL_SPHERE,
                    GRID_4x8, java.awt.Font.decode("Arial-ITALIC-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.cyan);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_B);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // Trenches & Ridges
        if (activeNamesList.contains(TRENCHESRIDGES)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_trenchesridges", fileCachePath, Sector.FULL_SPHERE,
                    GRID_4x8, java.awt.Font.decode("Arial-BOLDITALIC-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.cyan);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_B);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // Deserts & Plains
        if (activeNamesList.contains(DESERTSPLAINS)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_desertsplains", fileCachePath, Sector.FULL_SPHERE,
                    GRID_4x8, java.awt.Font.decode("Arial-BOLDITALIC-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.orange);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_B);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // Lakes & Rivers
        if (activeNamesList.contains(LAKESRIVERS)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_lakesrivers", fileCachePath, Sector.FULL_SPHERE,
                    GRID_8x16, java.awt.Font.decode("Arial-ITALIC-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.cyan);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_C);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // Mountains & Valleys
        if (activeNamesList.contains(MOUNTAINSVALLEYS)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_mountainsvalleys", fileCachePath, Sector.FULL_SPHERE,
                    GRID_8x16, java.awt.Font.decode("Arial-BOLDITALIC-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.orange);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_C);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // Countries
        if (activeNamesList.contains(COUNTRIES)) {
            placeNameService = new PlaceNameService(service, "topp:countries", fileCachePath, Sector.FULL_SPHERE, GRID_4x8,
                    java.awt.Font.decode("Arial-BOLD-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.white);
            placeNameService.setMinDisplayDistance(LEVEL_G);
            placeNameService.setMaxDisplayDistance(LEVEL_D);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // GeoNet World Capitals
        if (activeNamesList.contains(GEONET_P_PPLC)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_geonet_p_pplc", fileCachePath, Sector.FULL_SPHERE,
                    GRID_16x32,  java.awt.Font.decode("Arial-BOLD-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_D);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // World Cities >= 500k
        if (activeNamesList.contains(CITIESOVER500K)) {
            placeNameService = new PlaceNameService(service, "topp:citiesover500k", fileCachePath, Sector.FULL_SPHERE,
                    GRID_8x16, java.awt.Font.decode("Arial-BOLD-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(0);
            placeNameService.setMaxDisplayDistance(LEVEL_D);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // World Cities >= 100k
        if (activeNamesList.contains(CITIESOVER100K)) {
            placeNameService = new PlaceNameService(service, "topp:citiesover100k", fileCachePath, Sector.FULL_SPHERE,
                    GRID_16x32, java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(LEVEL_N);
            placeNameService.setMaxDisplayDistance(LEVEL_F);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // World Cities >= 50k and <100k
        if (activeNamesList.contains(CITIESOVER50K)) {
            placeNameService = new PlaceNameService(service, "topp:citiesover50k", fileCachePath, Sector.FULL_SPHERE,
                    GRID_16x32, java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(LEVEL_N);
            placeNameService.setMaxDisplayDistance(LEVEL_H);
            placeNameServiceSet.addService(placeNameService, false);
        }

        // World Cities >= 10k and <50k
        if (activeNamesList.contains(CITIESOVER10K)) {
            placeNameService = new PlaceNameService(service, "topp:citiesover10k", fileCachePath, Sector.FULL_SPHERE,
                    GRID_36x72, java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_I);
            placeNameServiceSet.addService(placeNameService, false);
        }

        // World Cities >= 1k and <10k
        if (activeNamesList.contains(CITIESOVER1K)) {
            placeNameService = new PlaceNameService(service, "topp:citiesover1k", fileCachePath, Sector.FULL_SPHERE,
                    GRID_36x72, java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_K);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // US Cities (Population Over 0)
        if (activeNamesList.contains(USCITIESOVER0)) {
            //values for masking sector pulled from wfs capabilities request
            Sector maskingSector = new Sector(Angle.fromDegrees(18.0), Angle.fromDegrees(70.7), Angle.fromDegrees(-176.66), Angle.fromDegrees(-66.0));
            placeNameService = new PlaceNameService(service, "topp:wpl_uscitiesover0", fileCachePath, maskingSector,
                    GRID_36x72, java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_N);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // US Cities (No Population)
        if (activeNamesList.contains(USCITIES0)) {
            //values for masking sector pulled from wfs capabilities request
            Sector maskingSector = new Sector(Angle.fromDegrees(-14.4), Angle.fromDegrees(71.3), Angle.fromDegrees(-176.66), Angle.fromDegrees(178.88));
            placeNameService = new PlaceNameService(service, "topp:wpl_uscities0", fileCachePath, maskingSector,
                    GRID_288x576, java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.orange);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_N);//M);
            placeNameServiceSet.addService(placeNameService, false);
        }

        // US Anthropogenic Features
        if (activeNamesList.contains(US_ANTHROPOGENIC)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_us_anthropogenic", fileCachePath, Sector.FULL_SPHERE, GRID_288x576,
                    java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.orange);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_P);
            placeNameServiceSet.addService(placeNameService, false);
        }

        // US Water Features
        if (activeNamesList.contains(US_WATER)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_us_water", fileCachePath, Sector.FULL_SPHERE, GRID_144x288,
                    java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.cyan);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_M);
            placeNameServiceSet.addService(placeNameService, false);
        }
       // US Terrain Features
        if (activeNamesList.contains(US_TERRAIN)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_us_terrain", fileCachePath, Sector.FULL_SPHERE, GRID_72x144,
                    java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.orange);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_O);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // GeoNET Administrative 1st Order
        if (activeNamesList.contains(GEONET_A_ADM1)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_geonet_a_adm1", fileCachePath, Sector.FULL_SPHERE, GRID_36x72,
                    java.awt.Font.decode("Arial-BOLD-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_N);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // GeoNET Administrative 2nd Order
        if (activeNamesList.contains(GEONET_A_ADM2)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_geonet_a_adm2", fileCachePath, Sector.FULL_SPHERE, GRID_36x72,
                    java.awt.Font.decode("Arial-BOLD-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.yellow);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_N);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // GeoNET Populated Place Administrative
        if (activeNamesList.contains(GEONET_P_PPLA)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_geonet_p_ppla", fileCachePath, Sector.FULL_SPHERE, GRID_36x72,
                    java.awt.Font.decode("Arial-BOLD-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.pink);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_N);
            placeNameServiceSet.addService(placeNameService, false);
        }
        // GeoNET Populated Place
        if (activeNamesList.contains(GEONET_P_PPL)) {
            placeNameService = new PlaceNameService(service, "topp:wpl_geonet_p_ppl", fileCachePath, Sector.FULL_SPHERE, GRID_36x72,
                    java.awt.Font.decode("Arial-PLAIN-10"), addVersionTag);
            placeNameService.setColor(java.awt.Color.pink);
            placeNameService.setMinDisplayDistance(0d);
            placeNameService.setMaxDisplayDistance(LEVEL_O);
            placeNameServiceSet.addService(placeNameService, false);
        }

        return placeNameServiceSet;
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment