How to get layers and their details of an online feature server (not just one layer)?

1195
8
12-13-2021 12:26 PM
RobertSchweikert
New Contributor II

Hi,

To access a single feature layer, we use :

 

ServiceFeatureTable featureTable = new ServiceFeatureTable("<FeatureLayerURL>");

 

How to get all the layers of a feature server from runtime java API? I mean we could start from 0 and then increment one by one and append to the last of URL, but how to access the server with all the layers directly, just for getting all the layer names and their fields information?

0 Kudos
8 Replies
MarkBaird
Esri Regular Contributor

@RobertSchweikert 

Using the service you mentioned in the other post on the forum, I can list the layers and the ids using the following code:

      // connect to the feature server
      ServiceGeodatabase gdb = new ServiceGeodatabase("https://services1.arcgis.com/owfRSBecxmXo3S0X/arcgis/rest/services/roads_database_ver_411gdb20211207t151917z001/FeatureServer");
      gdb.loadAsync();
      gdb.addDoneLoadingListener(()-> {
        System.out.println("gdb load status " + gdb.getLoadStatus());
        ArcGISFeatureServiceInfo serviceInfo = gdb.getServiceInfo();

        // list the layers
        for (IdInfo idInfo : serviceInfo.getLayerInfos()) {
          System.out.println("layer id = " + idInfo.getId() + " name = " + idInfo.getName());
        }
        
        // list the tables
        for(IdInfo idInfo : serviceInfo.getTableInfos()) {
          System.out.println("table id = " + idInfo.getId() + " name = " + idInfo.getName());
        }
      });

 

From each of the layers you can choose to load them from the ServiceFeatureTable class as you've mentioned above.

Does this help?

Also does this also answer the other question you posted?

RobertSchweikert
New Contributor II

Hi @MarkBaird , Thanks for the quick response. Using above I am able to get the layer details (Name and Id) of a feature server. But how do I get the attributes of one individual layer. By trying to load it as a feature table, the status comes "FAILED_TO_LOAD" for all the layers of the feature server. Are you able to load the individual layers of the above?

Below is the code I'm using for loading:

 

private ServiceFeatureTable getLoadedFeatureTable(String layerUrl) {
System.out.println("Accessing feature table..");
ServiceFeatureTable featureTable = new ServiceFeatureTable(layerUrl);
featureTable.loadAsync();
featureTable.addDoneLoadingListener(() -> {
System.out.println("Loading feature table");
});

while (featureTable.getLoadStatus() != LoadStatus.LOADED) {

if (featureTable.getLoadStatus() == LoadStatus.FAILED_TO_LOAD || featureTable.getLoadStatus() == LoadStatus.FAILED_TO_LOAD) {
return featureTable;
}
}
System.out.println("Feature Table Loading status: " + featureTable.getLoadStatus());

return featureTable;
}

FS URL : https://services1.arcgis.com/owfRSBecxmXo3S0X/arcgis/rest/services/roads_database_ver_411gdb20211207t151917z001/FeatureServer

 

0 Kudos
MarkBaird
Esri Regular Contributor

There is something curious going on with those feature services and my initial attempt also failed to load.  I'm going to take a closer look to see what is happening.

 

Can you give me any information on how you created the service?  

0 Kudos
RobertSchweikert
New Contributor II

I used import data functionality under layers and imported  the zip file containing GDB . It automatically created all the layers. Also the feature server is accessible through QGIS (I can see the layers and attribute definitions). Also it's visible through the ArcGIS 2D Map when we view the feature server. Just cannot access through Java API. Also is there no way to access just the attributes definition of the layers without actually loading the feature table, may be just using the serviceInfo?
The uploaded GDB file is shown here : https://developers.arcgis.com/layers/e8559fbe1dad4a4a9e4eb2272ce1b582/

It says Public (No Authentication Required), not sure if you can access this.

Item Id: e8559fbe1dad4a4a9e4eb2272ce1b582

0 Kudos
MarkBaird
Esri Regular Contributor

I've work out the issue.  The service doesn't appear to show it spatial reference until it has some data loaded in.  If it did, the table would load, but here a more robust approach which will work even if the service has no data:

      // create a map with the standard imagery basemap style
      ArcGISMap map = new ArcGISMap(Basemap.createLightGrayCanvas());


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

      // connect to the feature server
      String featureServer = "https://services1.arcgis.com/owfRSBecxmXo3S0X/arcgis/rest/services/roads_database_ver_411gdb20211207t151917z001/FeatureServer";

      ServiceGeodatabase gdb = new ServiceGeodatabase(featureServer);
      gdb.loadAsync();
      gdb.addDoneLoadingListener(()-> {
        System.out.println("gdb load status " + gdb.getLoadStatus());
        ArcGISFeatureServiceInfo serviceInfo = gdb.getServiceInfo();

        // list the layers

        for (IdInfo idInfo : serviceInfo.getLayerInfos()) {
          System.out.println("layer id = " + idInfo.getId() + " name = " + idInfo.getName());

          // crude limit to which layers we load
          if (idInfo.getId() < 5) {
            // create table
            ServiceFeatureTable table = new ServiceFeatureTable(featureServer + "/" + idInfo.getId());

            // make feature layer from table
            FeatureLayer featureLayer = new FeatureLayer(table);

            // create a listen to report back that it worked
            featureLayer.addDoneLoadingListener(()-> {
              System.out.println(" layer load status " + featureLayer.getLoadStatus());

              // assuming all is well try reading something from the table
              if (featureLayer.getLoadStatus() == LoadStatus.LOADED) {
                System.out.println("geometry type " + featureLayer.getFeatureTable().getGeometryType().toString());
              }
            });

            // add the layer to your map
            map.getOperationalLayers().add(featureLayer);
          }
        }

 

Does this help?

0 Kudos
RobertSchweikert
New Contributor II

Hi @MarkBaird , I used your code, but removed the Map parts of it as I don't need them for my processing. The layers still show NOT_LOADING as load status and the fields show empty. Below is the code I used:

 

String featureServer = "https://services1.arcgis" +
".com/owfRSBecxmXo3S0X/arcgis/rest/services" +
"/roads_database_ver_411gdb20211207t151917z001/FeatureServer";

ServiceGeodatabase gdb = new ServiceGeodatabase(featureServer);
gdb.loadAsync();
gdb.addDoneLoadingListener(() -> {
System.out.println("gdb load status " + gdb.getLoadStatus());
ArcGISFeatureServiceInfo serviceInfo = gdb.getServiceInfo();

// list the layers

for (IdInfo idInfo : serviceInfo.getLayerInfos()) {
System.out.println("layer id = " + idInfo.getId() + " name = " + idInfo.getName());

// crude limit to which layers we load
if (idInfo.getId() < 5) {
// create table
ServiceFeatureTable table =
new ServiceFeatureTable(featureServer + "/" + idInfo.getId());

// make feature layer from table
FeatureLayer featureLayer = new FeatureLayer(table);

// create a listen to report back that it worked
featureLayer.addDoneLoadingListener(() -> {
System.out.println(" layer load status " + featureLayer.getLoadStatus());

// assuming all is well try reading something from the table
if (featureLayer.getLoadStatus() == LoadStatus.LOADED) {
System.out.println("geometry type " + featureLayer.getFeatureTable().getGeometryType().toString());
}
});

while(featureLayer.getLoadStatus() != LoadStatus.LOADED){
if(featureLayer.getLoadStatus() == LoadStatus.FAILED_TO_LOAD || featureLayer.getLoadStatus() == LoadStatus.NOT_LOADED){
break;
}
}

System.out.println("Feature Layer Load Status : " + featureLayer.getLoadStatus());

// add the layer to your map
// map.getOperationalLayers().add(featureLayer);
}
}
}); 

 

Console Output:

 gdb load status LOADED
layer id = 0 name = Carriageway
Feature Layer Load Status : NOT_LOADED
Fields: []
layer id = 1 name = Road_Lines
Feature Layer Load Status : NOT_LOADED
Fields: []
layer id = 2 name = Road_Level
Feature Layer Load Status : NOT_LOADED
Fields: []
layer id = 3 name = Directional_Sign
Feature Layer Load Status : NOT_LOADED
Fields: []
layer id = 4 name = StreetLight_Pole
Feature Layer Load Status : NOT_LOADED
Fields: []
layer id = 5 name = StreetLight_Duct
layer id = 6 name = Tunnel_Light
layer id = 7 name = StreetLight_Cable
layer id = 8 name = StreetLight_FeederPillar
layer id = 9 name = Signal_Duct
layer id = 10 name = Traffic_Sign
layer id = 11 name = Detector_Loop
layer id = 12 name = Studs
layer id = 13 name = Inspection_Chamber
layer id = 14 name = Control_Box
layer id = 15 name = Traffic_Bollard
layer id = 16 name = Road_Marking_Polygon
layer id = 17 name = Road_Marking_Lines
layer id = 18 name = Traffic_Signal_Pole
layer id = 19 name = STRUCTURE
layer id = 20 name = ITS_3G_4G_Antenna
layer id = 21 name = ITS_Air_Quality_Monitor
layer id = 22 name = ITS_Auto_Incident_Detection_Camera
layer id = 23 name = ITS_Bluetooth_Assembly
layer id = 24 name = ITS_Box_Junction_Enforcement_Camera
layer id = 25 name = ITS_Detection_Point
layer id = 26 name = ITS_Fish_Eye_Lens_Camera
layer id = 27 name = ITS_Emergency_Roadway_Telephone
layer id = 28 name = ITS_Flashing_Amber_Warning_Light
layer id = 29 name = ITS_Fixed_CCTV_Camera
layer id = 30 name = ITS_Chamber
layer id = 31 name = ITS_Full_Dynamic_Message_Sign
layer id = 32 name = ITS_Pole
layer id = 33 name = ITS_Feeder_Pillar
layer id = 34 name = ITS_Enclosure
layer id = 35 name = ITS_Duct
layer id = 36 name = ITS_Transformer
layer id = 37 name = ITS_OVDS_Alarm
layer id = 38 name = ITS_Lane_Control_Sign
layer id = 39 name = ITS_Fibre_Optic_Cable
layer id = 40 name = ITS_Small_Dynamic_Message_Sign
layer id = 41 name = ITS_License_Plate_Reader
layer id = 42 name = ITS_Weigh_In_Motion_System
layer id = 43 name = ITS_Road_Weather_Information_System
layer id = 44 name = ITS_Parking_Management_Sign
layer id = 45 name = ITS_Pan_Tilt_Zoom_CCTV_Camera
layer id = 46 name = ITS_OVDS_Detection_Assembly
layer id = 47 name = Gate_Level

0 Kudos
MarkBaird
Esri Regular Contributor

There a few things going on here.

 - Your layers have got no data yet so with the current API, you can only work with them in a map (this would allow you to add data for example).  However once the layer is in a map you can access the table and layer information.

 - If the layers did have data (even it had been deleted) you would be able to load the tables and work with them directly.  To show this I added a point and removed it again from layer #2 and you will notice this now loads.

The workflows for using the API usually centre around displaying the data in a map.  I really need to understand what you are trying to do here.  Are you always going to be working with freshly created feature services which have no data?  

Once I understand what you are doing I can give you a solution or even make a change / improvement to the API to improve it for your workflow.

RobertSchweikert
New Contributor II

Thanks @MarkBaird , I'm able to get layer id 2 details now. However what I understand is, that not only I cannot retrieve attribute info for a fresh layer with no data, also I cannot programmatically create a feature using the Java API in this type of layer (without using maps and manually adding features) as it also requires me to first load the layer which is anyways failing. But what I fail to understand is when I create a new data layer online myself using 'create data' functionality, I'm able to load the layer fine and able to create features through the Java API. Now this is also an empty layer which never had any features, but this layer doesn't fail to load. How is this layer different from the previous one?

As far as my workflow is concerned, I got this GDB (with just schema details and no data) from someone for a project and I was suppose to explore it. From QGIS I was able to load it along with attribute details and also could see it in the ARC 2D Map. May be QGIS uses GDAL library to do that. So I thought if GDAL is able to do this then ESRI's own Java API will definitely do that, since I will be majorly using that. The workflow doesn't involve interaction with any maps. I need to take data from a source format (GDB in this case) to some target format(DWG/DXF/PostGIS etc.) and also provide some automatic data validations and corrections in between. Usually I would get layers to process which will have some data in them. But there could be a chance where I get these empty layers and have to fill data in them programmatically.

0 Kudos