View on GitHub Sample viewer app
Create contour lines from local raster data using a local geoprocessing package .gpkx
and the contour geoprocessing tool.
Use case
For executing offline geoprocessing tasks in your ArcGIS Maps SDK for Java apps via an offline (local) server.
How to use the sample
Contour Line Controls (Top Left):
Interval - Specifies the spacing between contour lines.
Generate Contours - Adds contour lines to map using interval.
Clear Results - Removes contour lines from map.
How it works
Create and run a local server with LocalServer.INSTANCE
.
Start the server asynchronously with Server.startAsync()
.
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.
Start a LocalGeoprocessingService
and run a GeoprocessingTask
.
Instantiate LocalGeoprocessingService(Url, ServiceType)
to create a local geoprocessing service.
Invoke LocalGeoprocessingService.start()
to start the service asynchronously.
Instantiate GeoprocessingTask(LocalGeoprocessingService.url() + "/Contour")
to create a geoprocessing task that uses the contour lines tool.
Create an instance of GeoprocessingParameters
and add a GeoprocessingDouble
as a parameter using setInterval
.
Instantiate GeoprocessingParameters(ExecutionType)
creates geoprocessing parameters.
Create a parameter using GeoprocessingParameters.getInputs().put("Interval", new GeoprocessingDouble(double))
with name "Interval" and with the interval set as its value.
Create and start a GeoprocessingJob
using the previous parameters.
Create a geoprocessing job with GeoprocessingTask.createJob(GeoprocessingParameters)
.
Start the job with GeoprocessingJob.start()
.
Add contour lines as an ArcGISMapImageLayer
to the map.
Get url from local geoprocessing service using LocalGeoprocessingService.getUrl()
.
Get server job id of geoprocessing job using GeoprocessingJob.getServerJobId()
.
Replace GPServer
from url with MapServer/jobs/jobId
, to get generate contour lines data.
Create a map image layer from that new url and add that layer to the map.
Relevant API
GeoprocessingDouble
GeoprocessingJob
GeoprocessingParameter
GeoprocessingParameters
GeoprocessingTask
LocalGeoprocessingService
LocalGeoprocessingService.ServiceType
LocalServer
LocalServerStatus
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 Maps SDK for Local Server are compatible with the version of ArcGIS Pro you use to create geoprocessing and map packages. For example, the ArcGIS Maps SDK for Java v100.11.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 Maps SDK for Java v100.11.0 to work with ArcGIS Maps SDK for 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
.
geoprocessing, local, offline, parameters, processing, service
Sample CodeLocalServerGeoprocessingController.java LocalServerGeoprocessingController.java LocalServerGeoprocessingSample.java
Use dark colors for code blocks Copy
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
/*
* 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_geoprocessing;
import java.io.File;
import java.util.Map;
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.ProgressBar;
import javafx.scene.control.TextField;
import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
import com.esri.arcgisruntime.concurrent.Job;
import com.esri.arcgisruntime.data.TileCache;
import com.esri.arcgisruntime.layers.ArcGISMapImageLayer;
import com.esri.arcgisruntime.layers.ArcGISTiledLayer;
import com.esri.arcgisruntime.loadable.LoadStatus;
import com.esri.arcgisruntime.localserver.LocalGeoprocessingService;
import com.esri.arcgisruntime.localserver.LocalGeoprocessingService.ServiceType;
import com.esri.arcgisruntime.localserver.LocalServer;
import com.esri.arcgisruntime.localserver.LocalServerStatus;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.BasemapStyle;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.tasks.geoprocessing.GeoprocessingDouble;
import com.esri.arcgisruntime.tasks.geoprocessing.GeoprocessingJob;
import com.esri.arcgisruntime.tasks.geoprocessing.GeoprocessingParameter;
import com.esri.arcgisruntime.tasks.geoprocessing.GeoprocessingParameters;
import com.esri.arcgisruntime.tasks.geoprocessing.GeoprocessingTask;
public class LocalServerGeoprocessingController {
@FXML private TextField txtInterval;
@FXML private Button btnGenerate;
@FXML private Button btnClear;
@FXML private ProgressBar progressBar;
@FXML private MapView mapView;
private ArcGISTiledLayer tiledLayer; // keep loadable in scope to avoid garbage collection
private GeoprocessingTask gpTask;
private LocalGeoprocessingService localGPService;
private static LocalServer server;
/**
* Called after FXML loads. Sets up scene and map and configures property bindings.
*/
public void initialize () {
try {
// 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 map with the light gray basemap style
ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_LIGHT_GRAY);
// set the map to the map view
mapView.setMap(map);
// load tiled layer and zoom to location
String rasterURL = new File(System.getProperty( "data.dir" ), "./samples-data/local_server/RasterHillshade.tpkx" ).getAbsolutePath();
TileCache tileCache = new TileCache(rasterURL);
tiledLayer = new ArcGISTiledLayer(tileCache);
tiledLayer.loadAsync();
tiledLayer.addDoneLoadingListener(() -> {
if (tiledLayer.getLoadStatus() == LoadStatus.LOADED) {
mapView.setViewpointGeometryAsync(tiledLayer.getFullExtent());
} else {
Alert alert = new Alert(Alert.AlertType.ERROR, "Tiled Layer Failed to Load!" );
alert.show();
}
});
map.getOperationalLayers().add(tiledLayer);
// check that local server install path can be accessed
if (LocalServer.INSTANCE.checkInstallValid()) {
progressBar.setVisible( true );
server = LocalServer.INSTANCE;
// start the local server
server.addStatusChangedListener(status -> {
if (server.getStatus() == LocalServerStatus.STARTED) {
try {
String gpServiceURL = new File(System.getProperty( "data.dir" ), "./samples-data/local_server/Contour.gpkx" ).getAbsolutePath();
// need map server result to add contour lines to map
localGPService =
new LocalGeoprocessingService(gpServiceURL, ServiceType.ASYNCHRONOUS_SUBMIT_WITH_MAP_SERVER_RESULT);
} catch (Exception e) {
e.printStackTrace();
}
localGPService.addStatusChangedListener(s -> {
// create geoprocessing task once local geoprocessing service is started
if (s.getNewStatus() == LocalServerStatus.STARTED) {
// add `/Contour` to use contour geoprocessing tool
gpTask = new GeoprocessingTask(localGPService.getUrl() + "/Contour" );
btnClear.disableProperty().bind(btnGenerate.disabledProperty().not());
btnGenerate.setDisable( false );
progressBar.setVisible( false );
}
});
localGPService.startAsync();
} else if (server.getStatus() == LocalServerStatus.FAILED) {
showMessage( "Local Geoprocessing Load Error" , "Local Geoprocessing Failed to load." );
}
});
server.startAsync();
} else {
showMessage( "Local Server Load Error" , "Local Server install path couldn't be located." );
}
} catch (Exception e) {
// on any exception, print the stack trace
e.printStackTrace();
}
}
/**
* Creates a Map Image Layer that displays contour lines on the map using the interval the that is set.
*/
@FXML
protected void handleGenerateContours () {
// tracking progress of creating contour map
progressBar.setVisible( true );
// create parameter using interval set
GeoprocessingParameters gpParameters = new GeoprocessingParameters(
GeoprocessingParameters.ExecutionType.ASYNCHRONOUS_SUBMIT);
final Map<String, GeoprocessingParameter> inputs = gpParameters.getInputs();
double interval = Double.parseDouble(txtInterval.getText());
inputs.put( "Interval" , new GeoprocessingDouble(interval));
// adds contour lines to map
GeoprocessingJob gpJob = gpTask.createJob(gpParameters);
gpJob.addProgressChangedListener(() -> progressBar.setProgress((( double ) gpJob.getProgress()) / 100 ));
gpJob.addJobDoneListener(() -> {
if (gpJob.getStatus() == Job.Status.SUCCEEDED) {
// creating map image url from local geoprocessing service url
String serviceUrl = localGPService.getUrl();
String mapServerUrl = serviceUrl.replace( "GPServer" , "MapServer/jobs/" + gpJob.getServerJobId());
ArcGISMapImageLayer mapImageLayer = new ArcGISMapImageLayer(mapServerUrl);
mapImageLayer.loadAsync();
mapView.getMap().getOperationalLayers().add(mapImageLayer);
btnGenerate.setDisable( true );
} else {
Alert dialog = new Alert(AlertType.ERROR);
dialog.setHeaderText( "Geoprocess Job Fail" );
dialog.setContentText( "Error: " + gpJob.getError().getMessage());
dialog.showAndWait();
}
progressBar.setVisible( false );
});
gpJob.start();
}
/**
* Removes contour lines from map if any are applied.
*/
@FXML
protected void handleClearResults () {
if (mapView.getMap().getOperationalLayers().size() > 1 ) {
mapView.getMap().getOperationalLayers().remove( 1 );
btnGenerate.setDisable( false );
}
}
private void showMessage (String title, String message) {
Platform.runLater(() -> {
Alert dialog = new Alert(AlertType.INFORMATION);
dialog.initOwner(mapView.getScene().getWindow());
dialog.setHeaderText(title);
dialog.setContentText(message);
dialog.showAndWait();
Platform.exit();
});
}
/**
* Stops and releases all resources used in application.
*/
void terminate () {
if (mapView != null ) {
mapView.dispose();
}
}
}