Browse OGC API feature service

View on GitHub
Sample viewer app

Browse an OGC API feature service for layers and add them to the map.

Image of browse OGC API feature service

Use case

OGC API standards are used for sharing geospatial data on the web. As an open standard, the OGC API aims to improve access to geospatial or location information and could be a good choice for sharing data internationally or between organizations. That data could be of any type, including, for example, transportation layers shared between government organizations and private businesses.

How to use the sample

Select a layer to display from the list of layers shown in an OGC API feature service.

How it works

  1. Create an OgcFeatureService with a URL to an OGC API feature service, and load it.
  2. Obtain the OgcFeatureServiceInfo with ogcFeatureService.getServiceInfo().
  3. Create a list of feature collections from the OGC feature service information with .getFeatureCollectionInfos().
  4. When a feature collection is selected, create an OgcFeatureCollectionTable from the OgcFeatureCollectionInfo.
  5. Populate the OgcFeatureCollectionTable using .populateFromServiceAsync() with QueryParameters.
  6. Create a FeatureLayer from the feature collection table.
  7. Add the feature layer to the ArcGISMap.

Relevant API

  • OgcFeatureCollectionInfo
  • OgcFeatureCollectionTable
  • OgcFeatureService
  • OgcFeatureServiceInfo

About the data

The Daraa, Syria test data is OpenStreetMap data converted to the Topographic Data Store schema of NGA.

Additional information

See the OGC API website for more information on the OGC API family of standards.

Tags

browse, catalog, feature, layers, OGC, OGC API, service, web

Sample Code

BrowseOgcApiFeatureServiceSample.java
                                                                                                                                                                                                                                                                                                          
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/*
 * Copyright 2021 Esri.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.esri.samples.browse_ogc_api_feature_service;

import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.FeatureQueryResult;
import com.esri.arcgisruntime.data.OgcFeatureCollectionTable;
import com.esri.arcgisruntime.data.QueryParameters;
import com.esri.arcgisruntime.data.ServiceFeatureTable;
import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.layers.FeatureLayer;
import com.esri.arcgisruntime.layers.OgcFeatureCollectionInfo;
import com.esri.arcgisruntime.layers.OgcFeatureService;
import com.esri.arcgisruntime.layers.OgcFeatureServiceInfo;
import com.esri.arcgisruntime.loadable.LoadStatus;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.BasemapStyle;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.symbology.ColorUtil;
import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
import com.esri.arcgisruntime.symbology.SimpleRenderer;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.stage.Stage;

import java.util.List;

public class BrowseOgcApiFeatureServiceSample extends Application {

  private ArcGISMap map;
  private MapView mapView;
  private ListView<OgcFeatureCollectionInfo> ogcLayerNamesListView;
  private OgcFeatureService ogcFeatureService; // keep loadable in scope to avoid garbage collection

  // UI class variables
  private ProgressIndicator progressIndicator;
  private TextField textField;
  private Button loadButton;
  private Button loadSelectedLayerButton;

  @Override
  public void start(Stage stage) {

    // create stack pane and JavaFX app scene
    StackPane stackPane = new StackPane();
    Scene scene = new Scene(stackPane);
    scene.getStylesheets().add(getClass().getResource("/browse_ogc_api_feature_service/style.css").toExternalForm());

    // set title, size, and add JavaFX scene to stage
    stage.setTitle("Browse OGC API Feature Service");
    stage.setWidth(800);
    stage.setHeight(700);
    stage.setScene(scene);
    stage.show();

    // authentication with an API key or named user is required to access basemaps and other location services
    String yourAPIKey = System.getProperty("apiKey");
    ArcGISRuntimeEnvironment.setApiKey(yourAPIKey);

    // create a progress indicator
    progressIndicator = new ProgressIndicator();
    progressIndicator.setVisible(false);

    // create a map with the topographic basemap style
    map = new ArcGISMap(BasemapStyle.ARCGIS_TOPOGRAPHIC);

    // create a map view and set the map to it
    mapView = new MapView();
    mapView.setMap(map);

    // add the map view, UI controls, and the progress indicator to the stack pane
    stackPane.getChildren().addAll(mapView, uiControlsVBox(), progressIndicator);

    // when the load button is clicked, load the provided OGC API service url
    loadButton.setOnAction(e -> loadOgcApiService(textField.getText()));

    // when the load selected layer button is clicked, load the selected layer from the list view
    loadSelectedLayerButton.setOnAction(e -> updateMap(ogcLayerNamesListView.getSelectionModel().getSelectedItem()));

  }

  /**
   * Loads an OGC feature service from the provided service URL string.
   *
   * @param serviceUrl the service url of the OGC feature service
   */
  private void loadOgcApiService(String serviceUrl) {

    // clear any previously loaded OGC layers from the list view, and show the progress indicator
    ogcLayerNamesListView.getItems().clear();
    progressIndicator.setVisible(true);

    // check if the text box is populated before instantiating and loading a new OGC feature service from the provided URL
    if (!textField.getText().isEmpty()) {

      ogcFeatureService = new OgcFeatureService(serviceUrl);
      ogcFeatureService.loadAsync();

      // when the feature service has loaded, get a list of its layers and add them to the list view
      ogcFeatureService.addDoneLoadingListener(() -> {
        if (ogcFeatureService.getLoadStatus() == LoadStatus.LOADED) {

          // hide progress indicator
          progressIndicator.setVisible(false);

          // get the service metadata and then a list of available collections
          OgcFeatureServiceInfo serviceInfo = ogcFeatureService.getServiceInfo();
          List<OgcFeatureCollectionInfo> layerList = serviceInfo.getFeatureCollectionInfos();
          ogcLayerNamesListView.getItems().addAll(layerList);

          // populate the list view with layer names
          ogcLayerNamesListView.setCellFactory(list -> new ListCell<>() {

            @Override
            protected void updateItem(OgcFeatureCollectionInfo ogcFeatureCollectionInfo, boolean bln) {
              super.updateItem(ogcFeatureCollectionInfo, bln);
              if (ogcFeatureCollectionInfo != null) {
                String titleOfOgcFeatureServiceLayer = ogcFeatureCollectionInfo.getTitle();
                setText(titleOfOgcFeatureServiceLayer);
              }
            }
          });
          // when a layer is selected, enable the load selected layer button
          ogcLayerNamesListView.setOnMouseClicked(e -> loadSelectedLayerButton.setDisable(false));

          // if the feature service fails to load, display an error
        } else {
          new Alert(Alert.AlertType.ERROR, "Failed to load OGC feature service").show();
          if (ogcFeatureService.getLoadError() !=  null) {
            ogcFeatureService.getLoadError().printStackTrace();
          }
          textField.clear();
          progressIndicator.setVisible(false);
        }
      });

      // if the text field is blank and the load button is clicked, display an error
    } else {
      new Alert(Alert.AlertType.ERROR, "Enter a service url to continue").show();
      progressIndicator.setVisible(false);
    }
  }

  /**
   * Adds an OGCFeatureCollectionInfo to the map's operational layers.
   *
   * @param ogcFeatureCollectionInfo the ogcFeatureCollectionInfo that the map will display
   */
  private void updateMap(OgcFeatureCollectionInfo ogcFeatureCollectionInfo) {

    progressIndicator.setVisible(true);

    // clear the map's operational layers
    map.getOperationalLayers().clear();

    // create an OGC feature collection table from the feature collection info
    var ogcFeatureCollectionTable = new OgcFeatureCollectionTable(ogcFeatureCollectionInfo);

    // set the feature request mode to manual
    // in this mode, the table must be manually populated as panning and zooming won't request features automatically.
    ogcFeatureCollectionTable.setFeatureRequestMode(ServiceFeatureTable.FeatureRequestMode.MANUAL_CACHE);

    // create new query parameters
    var queryParameters = new QueryParameters();
    // set a limit of 1000 on the number of returned features per request, the default on some services could be as low as 10
    queryParameters.setMaxFeatures(1000);

    try {
      // populate and load the table with the query parameters
      // set the clearCache parameter to false to include existing table entries, and set the outfields parameter to null to request all fields
      ListenableFuture<FeatureQueryResult> result = ogcFeatureCollectionTable.populateFromServiceAsync(queryParameters, false, null);
      result.addDoneListener(() -> progressIndicator.setVisible(false));

    } catch (Exception exception) {
      exception.printStackTrace();
      new Alert(Alert.AlertType.ERROR, exception.getMessage()).show();
    }

    // apply a renderer to the feature layer once the table is loaded (the renderer is based on the table's geometry type)
    ogcFeatureCollectionTable.addDoneLoadingListener(() -> {

      // create a feature layer to visualize the OGC features
      FeatureLayer ogcFeatureLayer = new FeatureLayer(ogcFeatureCollectionTable);

      switch (ogcFeatureCollectionTable.getGeometryType()) {
        case POINT:
        case MULTIPOINT:
          ogcFeatureLayer.setRenderer(new SimpleRenderer(
            new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, ColorUtil.colorToArgb(Color.BLUE), 5)));
          break;
        case POLYGON:
        case ENVELOPE:
          ogcFeatureLayer.setRenderer(new SimpleRenderer(
            new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, ColorUtil.colorToArgb(Color.BLUE), null)));
          break;
        case POLYLINE:
          ogcFeatureLayer.setRenderer(new SimpleRenderer(
            new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, ColorUtil.colorToArgb(Color.BLUE), 1)));
          break;
      }

      // add the layer to the map's operational layers
      map.getOperationalLayers().add(ogcFeatureLayer);

      // set the map view's viewpoint to the extent of the layer
      Envelope collectionExtent = ogcFeatureLayer.getFullExtent();
      if (!collectionExtent.isEmpty()) {
        mapView.setViewpointGeometryAsync(collectionExtent, 100);
      }
    });

  }

  /**
   * Sets up the user interaction controls by adding a text field, load button, list view and load selected layer button to a VBox.
   *
   * @return a VBox containing user interaction controls
   */
  private VBox uiControlsVBox() {

    // create a control panel
    VBox controlsVBox = new VBox(6);
    controlsVBox.setBackground(new Background(new BackgroundFill(Paint.valueOf("rgba(0,0,0,0.3)"), CornerRadii.EMPTY,
      Insets.EMPTY)));
    controlsVBox.setPadding(new Insets(10.0));
    controlsVBox.setMaxSize(300, 300);

    // create a text field for entering a service URL, and provide an example service url to start with
    textField = new TextField();
    textField.setMaxWidth(300);
    textField.setText("https://demo.ldproxy.net/daraa");

    // create a button that allows the provided service to be loaded
    loadButton = new Button("Load");

    // create a list view to show all of the layers in an OGC API feature service
    ogcLayerNamesListView = new ListView<>();
    ogcLayerNamesListView.setMaxSize(300, 250);

    // create a button that loads the layer selected in the list
    loadSelectedLayerButton = new Button("Load selected layer");
    loadSelectedLayerButton.setDisable(true);

    HBox hbox = new HBox(6);
    hbox.getChildren().addAll(textField, loadButton);
    HBox.setHgrow(textField, Priority.ALWAYS);
    controlsVBox.getChildren().addAll(hbox, ogcLayerNamesListView, loadSelectedLayerButton);
    StackPane.setAlignment(controlsVBox, Pos.TOP_LEFT);
    StackPane.setMargin(controlsVBox, new Insets(10, 0, 0, 10));

    return controlsVBox;

  }

  /**
   * Stops and releases all resources used in application.
   */
  @Override
  public void stop() {
    if (mapView != null) {
      mapView.dispose();
    }
  }

  /**
   * Opens and runs application.
   *
   * @param args arguments passed to this application
   */
  public static void main(String[] args) {

    Application.launch(args);
  }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.