Hello,
I have a published mapservice. Using Javascript APIs, I want to get the datasource (Featureclass name) of a specific featurelayer in that mapservice. Is it possible ?
Thanks,
Rami.
Rami,
I have wanted to do the same and that information is just not available for the REST endpoint.
I've come up with the following workaround:
I've created a Python script that can get the datasource of a featurelayer from a mapservice.
Then I've shared this script as a Geoprocessing service that can be consumed via REST or ArcGIS API e.g. ArcGIS API for Javascript.
pythontoolbox
Here is the full script. It's a Python toolbox.
#====================================Python Toolbox===================================
#-------------------------------------------------------------------------------
# Name: GetLayerDataSource
# Purpose: A script that get the dataset name (Full path of the featureclass) of a layer in a map service.
#
# Author: rami.ghali
#
# Created: 20/04/2015
# How to use:
# 1- At [GetLayerDataSource], apply your modifications to set the proper values of the AGS name, port, uname, and password.
# 2- Test the tool
# 3- Share the tool as a geoprocessing service
# 4- Consume the shared Geoprocessing service via ArcGIS API to get the dataset names of layers in a mapservice.
#-------------------------------------------------------------------------------
import arcpy
import httplib, urllib
import json,sys,os
class Toolbox(object):
def __init__(self):
"""Define the toolbox (the name of the toolbox is the name of the
.pyt file)."""
self.label = "GetDataSource"
self.alias = ""
# List of tool classes associated with this toolbox
self.tools = [GetLayerDataSource]
class GetLayerDataSource(object):
def __init__(self):
"""Define the tool (tool name is the name of the class)."""
self.label = "Get Layer DataSource"
self.description = "Get datasource of featurelayer"
self.canRunInBackground = False
def getParameterInfo(self):
"""Define parameter definitions"""
in_mapservice_name = arcpy.Parameter(displayName="Mapservice Name",name="in_mapservice_name",
datatype="String",parameterType="Required",direction="Input")
in_mapservice_name.value = ""
in_layer_names = arcpy.Parameter(displayName="Layer Names",name="in_layer_names",
datatype="String",parameterType="Required",direction="Input")
in_layer_names.value = ""
out_response = arcpy.Parameter(displayName="Response",name="out_response",
datatype="String",parameterType="Derived",direction="Output")
params = [in_mapservice_name,in_layer_names,out_response]
return params
def isLicensed(self):
"""Set whether tool is licensed to execute."""
return True
def updateParameters(self, parameters):
"""Modify the values and properties of parameters before internal
validation is performed. This method is called whenever a parameter
has been changed."""
return
def updateMessages(self, parameters):
"""Modify the messages created by internal validation for each tool
parameter. This method is called after internal validation."""
return
def execute(self, parameters, messages):
"""The source code of the tool."""
#Read input parameters
arcpy.AddMessage("Reading input parameters")
in_mapservice_name = "AdminAreasNOC_EN"#parameters[0].valueAsText
in_layer_names = "Emirate_District,AreaNames"#parameters[1].valueAsText
#You can read the following values from a config file
serverName = "192.168.9.30"
serverPort = "6080"
serverUName = "siteadmin"
serverPwd = "Pa$$w0rd"
response = []
datasetName = ""
try:
if not in_layer_names or not in_mapservice_name:
arcpy.AddMessage("Invalid input parameters")
else:
#Get Filepath of the map service
filePath = GetMapServiceFilePath(serverName,serverPort,serverUName,serverPwd,in_mapservice_name)
if filePath and os.path.exists(filePath.replace("msd","mxd")):
arcpy.AddMessage("MapDocument path is valid")
mxd = arcpy.mapping.MapDocument(filePath.replace("msd","mxd"))
if mxd:
arcpy.AddMessage("MapDocument has been loaded")
if "," in in_layer_names:
lst_layer_names = in_layer_names.split(",")
else:
lst_layer_names.append(in_layer_names)
for layer_name in lst_layer_names:
lyr = arcpy.mapping.ListLayers(mxd,layer_name)[0]
datasetName = ""
if lyr:
if lyr.supports("datasetName"):
datasetName = lyr.datasetName
del lyr
else:
arcpy.AddMessage("Couldn't load layer {0}".format(layer_name))
response.append({'layer': layer_name,'datasetName':datasetName})
del mxd
json.dumps(response)
#If an error occurs while running a tool
except arcpy.ExecuteError:
arcpy.AddMessage(arcpy.GetMessages(0))
arcpy.AddMessage(arcpy.GetMessages(1))
arcpy.AddMessage(arcpy.GetMessages(2))
#If any other error occurs
except Exception as e:
arcpy.AddMessage(str(e))
parameters[2].value = str(response)
def GetMapServiceFilePath(serverName,serverPort,uname,password,serviceName):
filePath = ""
try:
if serverName and serverPort and uname and password:
# Get a token
token = getToken(uname, password, serverName, serverPort)
# Get the root info
serverURL = "/arcgis/admin/services/"
# This request only needs the token and the response formatting parameter
params = urllib.urlencode({'token': token, 'f': 'json'})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
# Connect to URL and post parameters
httpConn = httplib.HTTPConnection(serverName, serverPort)
httpConn.request("POST", serverURL, params, headers)
# Read response
response = httpConn.getresponse()
if (response.status != 200):
httpConn.close()
print "Could not read folder information."
return
else:
data = response.read()
# Check that data returned is not an error object
if not assertJsonSuccess(data):
arcpy.AddMessage("Error when reading server information. " + str(data))
return
else:
arcpy.AddMessage("Processed server information successfully. Now processing folders...")
# Deserialize response into Python object
dataObj = json.loads(data)
httpConn.close()
#Store the Folders in a list to loop on
folders = dataObj["folders"]
#Remove the System and Utilities folders
folders.remove("System")
#folders.remove("Utilities")
#Add an entry for the root folder
folders.append("")
#Loop on the found folders and discover the services and write the service information
for folder in folders:
# Determine if the loop is working on the root folder or not
if folder != "":
folder += "/"
# Build the URL for the current folder
folderURL = "/arcgis/admin/services/" + folder
params = urllib.urlencode({'token': token, 'f': 'json'})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
# Connect to URL and post parameters
httpConn = httplib.HTTPConnection(serverName, serverPort)
httpConn.request("POST", folderURL, params, headers)
# Read response
response = httpConn.getresponse()
if (response.status != 200):
httpConn.close()
arcpy.AddMessage("Could not read folder information.")
return
else:
data = response.read()
# Check that data returned is not an error object
if not assertJsonSuccess(data):
arcpy.AddMessage("Error when reading folder information. " + str(data))
else:
arcpy.AddMessage("Processed folder information successfully. Now processing services...")
# Deserialize response into Python object
dataObj = json.loads(data)
httpConn.close()
# Loop through each service in the folder
for item in dataObj['services']:
if item["type"] == "MapServer" and str(item["serviceName"]).lower() == serviceName.lower():
# Build the Service URL
if folder:
sUrl = "/arcgis/admin/services/%s%s.%s" %(folder,item["serviceName"], item["type"])
else:
sUrl = "/arcgis/admin/services/%s.%s" %(item["serviceName"], item["type"])
# Submit the request to the server
httpConn.request("POST", sUrl, params, headers)
# Get the response
servResponse = httpConn.getresponse()
readData = servResponse.read()
jsonOBJ = json.loads(readData)
# get file path of the service
filePath = jsonOBJ["properties"]["filePath"]
return filePath
else:
# Close the connection to the current service
httpConn.close()
else:
arcpy.AddMessage("Invalid input parameters")
except Exception as e:
print str(e)
return filePath
def getToken(username, password, serverName, serverPort):
# Token URL is typically http://server[:port]/arcgis/admin/generateToken
tokenURL = "/arcgis/admin/generateToken"
params = urllib.urlencode({'username': username, 'password': password, 'client': 'requestip', 'f': 'json'})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
# Connect to URL and post parameters
httpConn = httplib.HTTPConnection(serverName, serverPort)
httpConn.request("POST", tokenURL, params, headers)
# Read response
response = httpConn.getresponse()
if (response.status != 200):
httpConn.close()
print "Error while fetching tokens from admin URL. Please check the URL and try again."
return
else:
data = response.read()
httpConn.close()
# Check that data returned is not an error object
if not assertJsonSuccess(data):
return
# Extract the token from it
token = json.loads(data)
return token['token']
# A function that checks that the input JSON object
# is not an error object.
def assertJsonSuccess(data):
obj = json.loads(data)
if 'status' in obj and obj['status'] == "error":
print "Error: JSON object returns an error. " + str(obj)
return False
else:
return True
===============================================================================I hope that helps.
Regards,
Rami.
Dear Rami,
Idk what is exactly the case, but I think you should publish a FeatureService in order to access to the data-source from REST. more details
Dear Yusuf,
The case is that I want to get the dataset (featureclass) name of a specific featurelayer in a mapservice.
REST doesb't provide these info so, I've created geoprocessing service to do the job by accessing the MXD of the mapservice and get the dataset name of the requested layers.
Regards,
Rami.