Access Layer Datasource of a MapService From REST

4905
4
04-08-2015 02:17 AM
RamiGhali2
New Contributor II

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.

Tags (1)
0 Kudos
4 Replies
RobertScheitlin__GISP
MVP Emeritus

Rami,

   I have wanted to do the same and that information is just not available for the REST endpoint.

0 Kudos
RamiGhali2
New Contributor II

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.

YousefQuran
Occasional Contributor

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

0 Kudos
RamiGhali2
New Contributor II

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.