2

I am working on a JavaScript (JS) app where the user draws a polygon and then a python-based Geoprocessing (GP) Service task queries the parcels and generates mailing labels. The GP task works great, but once the PDF is created I need to open the hyperlink in a new tab.

What I really need to get at is the return of my Python function:

# as a trivial example:
def myFunc(*args):
    # do something
    return output_url  # this is what I want to access!

So in my gp task, the function is returning the hyperlink url needed to download the report. I do not think there is an out of the box way to get the gp result. So the other thing I am thinking is to parse the messages returned from the GP Service. I have looked through the help docs and do not see a sample how to get at the messages. I'm new the JS development, so it's probably there and I'm just missing it.

My call to the gp task:

var gp = new Geoprocessor("http://myServer.com/arcgis/rest/services/GP_TASKS/MailingLabels/GPServer/MailingLabels");

function OpenInNewTab(url) {
    var win = window.open(url, '_blank');
    win.focus();
  };  

var gpParams = {
    "Boundary": fs,
    "Site": "Paynesville",
    "Mailing_Type": "taxpayer"
  };
gp.execute(gpParams);
var URL = ""; #need to get this from result OR parse messages

gp.on("execute-complete", OpenInNewTab(URL));

And here is an example of the JSON from the GP service messages:

{
 "results": [

 ],
 "messages": [
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Executing (MailingLabels): MailingLabels \"Feature Set\" Paynesville taxpayer"
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Start Time: Wed Mar 25 11:29:45 2015"
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Executing (MailingLabels): MailingLabels \"Feature Set\" Paynesville taxpayer"
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Start Time: Wed Mar 25 11:29:45 2015"
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Running script MailingLabels..."
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Creating labels in Avery 5160 format"
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "\nCreated \\\\arcserver2\\wwwroot\\TempFiles\\MailingLabels_taxpayer20150325112946.pdf\n"
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "http://myServer.com/TempFiles/MailingLabels_taxpayer20150325112946.pdf"
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Completed script MailingLabels..."
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Succeeded at Wed Mar 25 11:29:47 2015 (Elapsed Time: 1.85 seconds)"
  },
  {
   "type": "esriJobMessageTypeInformative",
   "description": "Succeeded at Wed Mar 25 11:29:47 2015 (Elapsed Time: 1.85 seconds)"
  }
 ]
}

There is nothing in the "results", so since I am actually printing out the URL needed in the messages, I'm thinking I can parse these somehow. So my questions are:

  1. Is there a way I can get the return URL from my Python function back as a result from the GP Service?

  2. If the answer to number 1 is no, how do I get at the result messages and step through them? This is a Synchronous task so I am using the execute() method.

  • 1
    This post (gis.stackexchange.com/questions/18464/…) might be helpful. They're outputting a table, but you might be able to do something similar with your URL. – Branco Mar 25 '15 at 18:04
  • Beautiful! This does look promising. I'll give that a try. – crmackey Mar 25 '15 at 18:15
3

I'd really recommend against parsing the output messages. For one, it'll be tedious. And more importantly, 2, you have INFO level messages on. INFO level displays path information to resources on the Server machine. Many people would consider this a security risk (leaving this level of information available to anyone consuming a service)

So here's some JavaScript code (async consumption) that returns the URL to a file produced by a GP Service. It shouldn't be much to hack it to support execute (sync).

[javascript code]

gp.submitJob(params, gpJobComplete, gpJobStatus, function(error){
          alert(error);     

function gpJobComplete(jobInfo) {  

      if(jobInfo.jobStatus == "esriJobFailed") {                            
        dojo.byId('downURL').innerHTML = "Failed to generate text file";        
       }    
       else if (jobInfo.jobStatus == "esriJobSucceeded") {                  
            gp.getResultData(jobInfo.jobId,"Output_Text_File", downloadFile);           
      }
    }    

    function downloadFile(outputFile) {  

       var theurl = outputFile.value.url;
//or you could insert a TARGET= ____ for an appropriate action in the <a>
       dojo.byId('downURL').innerHTML = "<a href='"+ theurl + "'>Download File (right-click, save-as)</a>";  
    }   

//Heres a function that gets and stuffs all the messages into a global var and updates a dojo text box
    function gpJobStatus(jobInfo) {  

       for (m, ml=jobInfo.messages.length; m<ml; m++) {
          xMsgs += jobInfo.messages[m]["description"] + "\n";               
       }        
        dojo.byId('messages').value = xMsgs;

    }   

[/javascript code]

[htmlcode]

//this produces a new, in-line clickable link from the downloadFile function
  <div id="downloadURLDiv">    
    <span id="downURL"></span>
  </div> 

[/htmlcode]

  • Thanks Kevin, I'll give this a try! I actually got the idea of parsing the arguments from your GP Session at the Dev Summit a few weeks ago :) Glad to know this is a better solution. – crmackey Mar 25 '15 at 18:43
  • Cool, if you understand parsing, I'll point this out. The GP Framework returns a URL to a file to download (http ://yourserver). The tool itself, through execution can only provide you the location on disk that the file gets saved to. You (tool author) would have to have knowledge of server virtual dirs and server paths to return that path in a message. On top of that, you (tool author) are now responsible for making sure if 2 people run the service at the same time, that files arent trying to overwrite each other and return wrong paths to the consumer. – KHibma Mar 25 '15 at 18:49
  • Yeah, I am not going to go the parsing route. I don't want to expose the info messages. I am experimenting with an output parameter (arcpy.SetParameter(3, OUT_URL)) right before the script ends with the hyperlink URL. – crmackey Mar 25 '15 at 18:56
  • 1
    You dont even need to go that far. Just pass your CSV, TXT, PDF? output into the SetParameter. The GP Framework will handle sending the URL to the JavaScript client. This code uses the output param name 'Output_Text_File': gp.getResultData(jobInfo.jobId,"Output_Text_File", downloadFile); and gets the value from it. (which .valee.url that the framework supplied) – KHibma Mar 25 '15 at 19:07
2

After beating my head against the wall and wondering why I could not get the results back from the gp.getResultData, I went back to the documentation. As it turns out, this method is only valid for Asynchronous tasks. So, to solve this I had to do two things:

Python function:

def someFunc(*args):
    # do stuff
    arcpy.SetParameter(3, out_url) #this was an output param
    return

Then in JavaScript:

function generateMailingLabels() {

    var features = [];
    features.push(new Graphic(geometryInput));
    var fs = new FeatureSet();
    fs.features = features;

    gp = new Geoprocessor("http://myServer.com/arcgis/rest/services/GP_TASKS/MailingLabels/GPServer/MailingLabels");

    var gpParams = {
        "Boundary": fs,
        "Site": "Paynesville",
        "Mailing_Type": "taxpayer"
    }

    gp.execute(gpParams, gpJobComplete);
};

function gpJobComplete(results, messages) {
    var theurl = results[0].value;
    OpenInNewTab(theurl);
};

//user needs to make sure they are allowing pop-ups!
function OpenInNewTab(url) {
    var win = window.open(url, '_blank');
    win.focus();
};

Thanks to @Khimba and @Branco for the help.

  • Out of curiosity, what are you using to format the mailing labels? – ianbroad Dec 23 '15 at 4:48
  • I'm using a python script to generate avery5160 labels. I have this posted here from a workshop I recently taught. This is just the function but I believe what I was using for the GP Service is also in the repo somewhere. – crmackey Dec 23 '15 at 14:34
  • Thanks I'll take a look. I was more wondering if you used a module such as pylabels to help with formatting the pdf. – ianbroad Dec 23 '15 at 14:51
  • Nope, just reportlab. I've never heard of pylabels. One disclaimer about the function I have...Based on the font size you use, the math has to be adjusted based on font size. When using font size 10 or 11 (and maybe 12?), the function I supplied should always format them as avery 5160. – crmackey Dec 23 '15 at 15:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.