Local Server services

View on GitHub
Sample viewer app

Demonstrates how to start and stop the Local Server and start and stop a local map, feature, and geoprocessing service running on the Local Server.

Image of local server services

Use case

For executing offline geoprocessing tasks in your ArcGIS Runtime apps via an offline (local) server.

How to use the sample

Choose an option from the dropdown control to filter packages by service type. Then click the Open button to choose a package. Finally, click the Start button to start the service. The service's status will be displayed in the center log.

To stop a service, select it from the Running Services list and click the Stop Service button. To go to the service's URL in your default web browser, select it and click the Go to URL button.

How it works

To start a LocalServer and attach a LocalService:

  1. Create and run a local server with LocalServer.INSTANCE.
  2. Start the server asynchronously with Server.startAsync().
  3. Wait for server to be in the LocalServerStatus.STARTED state.

    • Callbacks attached to Server.addStatusChangedListener() will invoke whenever the status of the local server has changed.
  4. Create and run a local service. Here is an example of running a LocalMapService:

    1. Instantiate LocalMapService(Url) to create a local map service with the given URL path to map package (mpk or mpkx file).
    2. Start the job with LocalMapService.startAsync().

      • The service is added to the LocalServer automatically.

To stop a LocalServer and any attached LocalServices:

  1. If required, you can retrieve a list of all running services with LocalServer.INSTANCE.getServices().
  2. Stop the services asynchronously using LocalService.stopAsync().
  3. Use LocalServer.INSTANCE.stopAsync() to stop the server asynchronously. You can use .addDoneListener() on this process to perform additional actions after the server is successfully stopped, such as removing temporary files.

Relevant API

  • LocalFeatureService
  • LocalGeoprocessingService
  • LocalMapService
  • LocalServer
  • LocalServerStatus
  • LocalService

Additional information

Local Server can be downloaded for Windows and Linux platforms from your ArcGIS Developers dashboard. Local Server is not supported on macOS.

Specific versions of ArcGIS Runtime Local Server are compatible with the version of ArcGIS Pro you use to create geoprocessing and map packages. For example, the ArcGIS Runtime API for Java v100.10.0 is configured for Local Server v100.10.0 which provides compatibility for packages created with ArcGIS Pro 2.7.x. For more information see the ArcGIS Developers guide.

To configure the ArcGIS Runtime API for Java v100.10.0 to work with Local Server 100.9.0:

  • Development machine:

    • Locate the Local Server installation directory and rename the folder from LocalServer100.9 to LocalServer100.10.
    • Update the environment variable from RUNTIME_LOCAL_SERVER_100_9 to RUNTIME_LOCAL_SERVER_100_10.
  • Deployment machine(s): Rename the deployment folder included with your application (or referenced by the LocalServerEnvironment.InstallPath property) from LocalServer100.9 to LocalServer100.10.

Tags

feature, geoprocessing, local services, map, server, service

Sample Code

LocalServerServicesController.javaLocalServerServicesSample.javamain.fxml
                                                                                                                                                                                                                                        
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
/*
 * Copyright 2017 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.local_server_services;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import javafx.application.HostServices;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import org.apache.commons.io.FileUtils;

import com.esri.arcgisruntime.localserver.LocalFeatureService;
import com.esri.arcgisruntime.localserver.LocalGeoprocessingService;
import com.esri.arcgisruntime.localserver.LocalMapService;
import com.esri.arcgisruntime.localserver.LocalServer;
import com.esri.arcgisruntime.localserver.LocalServerStatus;
import com.esri.arcgisruntime.localserver.LocalService;

public class LocalServerServicesController {

  @FXML private TextField packagePath;
  @FXML private ComboBox<String> serviceOptions;
  @FXML private Button startServiceButton;
  @FXML private TextArea statusLog;
  @FXML private ListView<LocalService> runningServices;
  @FXML private Button stopServiceButton;

  private HostServices hostServices;
  private FileChooser packageChooser;
  private Path appDataPath;

  @FXML
  private void initialize() {

    if (LocalServer.INSTANCE.checkInstallValid()) {
      LocalServer server = LocalServer.INSTANCE;

      // configure app data path (path length must be short for some services)
      appDataPath = Path.of(System.getProperty("user.home"), "EsriSamples");
      if (!appDataPath.toFile().exists()) {
        try {
          Files.createDirectory(appDataPath);
        } catch (IOException ex) {
          new Alert(AlertType.ERROR, "Failed to set local server app data path. Some processes may not work.").show();
        }
      }
      LocalServer.INSTANCE.setAppDataPath(appDataPath.toFile().getAbsolutePath());

      // log the server status
      server.addStatusChangedListener(status -> statusLog.appendText("Server Status: " + status.getNewStatus()
          .toString() + "\n"));
      // start the local server
      server.startAsync();
    } else {
      Platform.runLater(() -> {
        Alert dialog = new Alert(AlertType.INFORMATION);
        dialog.initOwner(stopServiceButton.getScene().getWindow());
        dialog.setHeaderText("Local Server Load Error");
        dialog.setContentText("Local Server install path couldn't be located.");
        dialog.showAndWait();

        Platform.exit();
      });
    }
    // create a file chooser to select package files
    packageChooser = new FileChooser();
    packagePath.textProperty().bind(packageChooser.initialFileNameProperty());
    packageChooser.setInitialDirectory(new File(System.getProperty("data.dir"), "./samples-data/local_server"));
    packageChooser.setInitialFileName(packageChooser.getInitialDirectory().getAbsolutePath() + "/PointsOfInterest.mpk");

    // create filters to choose files for specific services
    ExtensionFilter mpkFilter = new ExtensionFilter("Map Packages (*.mpk, *.mpkx)", "*.mpk", "*.mpkx");
    ExtensionFilter gpkFilter = new ExtensionFilter("Geoprocessing Packages (*.gpk, *.gpkx)", "*.gpk", "*.gpkx");
    packageChooser.getExtensionFilters().add(mpkFilter);

    // use the ComboBox to select a filter
    serviceOptions.getSelectionModel().selectedItemProperty().addListener(o -> {
      packageChooser.setInitialFileName(null);
      packageChooser.getExtensionFilters().clear();
      if ("Geoprocessing Service".equals(serviceOptions.getSelectionModel().getSelectedItem())) {
        packageChooser.getExtensionFilters().add(gpkFilter);
      } else {
        packageChooser.getExtensionFilters().add(mpkFilter);
      }
    });

    // create list view representation of running services
    runningServices.setCellFactory(list -> new ListCell<>() {

      @Override
      protected void updateItem(LocalService service, boolean bln) {

        super.updateItem(service, bln);
        if (service != null) {
          setText(service.getName() + "  :  " + service.getUrl());
        } else {
          setText(null);
        }
      }

    });

    // setup UI bindings
    stopServiceButton.disableProperty().bind(runningServices.getSelectionModel().selectedItemProperty().isNull());
    startServiceButton.disableProperty().bind(packageChooser.initialFileNameProperty().isNull());
  }

  /**
   * Creates and starts the selected service.
   */
  @FXML
  private void startSelectedService() {

    String selected = serviceOptions.getSelectionModel().getSelectedItem();
    // create local service
    final LocalService localService;
    final String serviceUrl = packageChooser.getInitialFileName();
    switch (selected) {
      case "Map Service":
        localService = new LocalMapService(serviceUrl);
        break;
      case "Feature Service":
        localService = new LocalFeatureService(serviceUrl);
        break;
      case "Geoprocessing Service":
        localService = new LocalGeoprocessingService(serviceUrl);
        break;
      default:
        localService = null;
    }

    // start local service and watch for updates
    if (localService != null) {
      localService.addStatusChangedListener(status -> {
        statusLog.appendText(selected + " Status: " + status.getNewStatus().toString() + "\n");
        if (status.getNewStatus() == LocalServerStatus.STARTED) {
          Platform.runLater(() -> runningServices.getItems().add(localService));
        }
      });
      localService.startAsync();
    }
  }

  /**
   * Opens a dialog to choose a package file.
   */
  @FXML
  private void openPackage() {

    File selectedFile = packageChooser.showOpenDialog(packagePath.getScene().getWindow());
    if (selectedFile != null) {
      packageChooser.setInitialDirectory(selectedFile.getParentFile());
      packageChooser.setInitialFileName(selectedFile.getAbsolutePath());
    }
  }

  /**
   * Stops the selected service from the running services list.
   */
  @FXML
  private void stopSelectedService() {

    LocalService selectedService = runningServices.getSelectionModel().getSelectedItem();
    selectedService.stopAsync();
    runningServices.getItems().remove(selectedService);
  }

  /**
   * Opens a browser to the url of the selected service.
   */
  @FXML
  private void openServiceURL() {

    String url = runningServices.getSelectionModel().getSelectedItem().getUrl();
    hostServices.showDocument(url);
  }

  /**
   * Allows access to the Host Services of the main JavaFX application.
   *
   * @param hostServices Hosted Services from main JavaFX application
   */
  void setHostServices(HostServices hostServices) {

    this.hostServices = hostServices;
  }

  /**
   * Stops and releases all resources used in application.
   */
  void terminate() {

    // make sure all services are stopped before deleting app data
    LocalServer.INSTANCE.stopAsync().addDoneListener(() -> {
      if (appDataPath != null) {
        try {
          // delete the app data
          FileUtils.deleteDirectory(appDataPath.toFile());
        } catch (IOException ex) {
          ex.printStackTrace();
        }
      }
    });
  }
}

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