Why?
LiveCycle Designer has a graphical way of defining a Web Service invocation – you simply create a new Data Connection based on a WSDL definition, and Designer creates all the input and output fields you need, along with a Submit button.
However, you can also quite easily invoke a Web Services from a PDF SmartForm without this visual designer – you just have to write a little code. Luckily the thoughtful PDF team gave us some really easy ways to invoke Web Services programmatically and you can do it in just a few lines.
Using code actually has some benefits over the visual technique that Designer uses, because:
- Often you don’t simply want to simply display the result, you want to process it in some way. For example, you may want to use the results to populate a drop-down list, or use the return value to validate some data.
- You may want to call a different instance of the web service depending on whether you are in a development, test or production environment. This can be quite hard to do in the visual paradigm, but is very easy to do in code.
- You get more control over error handling – as we shall soon see.
- There are some Web Services that are too complex to be handled by the graphical designer – but can still be invoked programmatically.
A Simple Example
Let’s start by looking at a very simple Web Service that converts temperatures from Fahrenheit To Celcius. (Note – you would almost certainly NOT use a web service to implement such a simple service – this could be implemented in a few lines of JavaScript within your form – but it serves as a useful example.)
The code to invoke this service is shown below:
var cURL = "http://webservices.daehosting.com/services/TemperatureConversions.wso?WSDL"; SOAP.wireDump = false; var service = SOAP.connect(cURL); var Input = {nFahrenheit:33}; var result = service.FahrenheitToCelcius(Input); xfa.host.messageBox(result);
The bits displayed in blue are the bits you need to change for different web services – most of the code is the same every time.
Let’s look at it line by line.
var cURL = "http://webservices.daehosting.com/services/TemperatureConversions.wso?WSDL";
First we need to identify to Acrobat/Reader the definition of the service. You do this by specifying the WSDL (or Web Services Definition Language) for the service. Acrobat/Reader will use this to understand where and how to invoke the service. The WSDL URL is exactly the same URL you would use in Designer when defining the WSDL Data Connection. Your IT department should be able to give you the URL for any services you may want to invoke.
In this case, we have hard-coded the location of the web service. But you could also insert a different hostname depending on whether your form was running in a test or production environment.
SOAP.wireDump = false;
This line can be very useful. If you set it to “true” instead of “false”, it will output a whole lot of really useful information to the Reader/Acrobat console. If you set it to “true”, you should always set it back to false when you’re done, as this is a global setting, which affects any other web-services invocations.
var service = SOAP.connect(cURL);
This line “connects” Reader/Acrobat to the web service. This line is always the same for any web service.
I’m going to skip the Input line for the moment, and come back to it later. Let’s take a look at the actual invocation:
var result = service.FahrenheitToCelcius(Input);
How did I know what method to invoke on the service object? Or more simply, how did I know to type “FahrenheitToCelcius”?
One way would to become a Web Services guru, and actually read the WSDL file. But that’s way too hard for most of us, so it’s easiest to use an existing software tool to work it out for us. My two favourite options are:
- LiveCycle Designer. Just add the WSDL Data Connection in Designer. As part of the Data Connect Wizard, it will ask you which operation you want to invoke. Take a note of this operation name, or copy it to your clipboard. You can see this in the screenshot below.

Operations In Designer
- SOAPUI. http:// http://www.soapui.org/ This handy (and free) tool generates a sample XML document for any Web Service you point it at.

Operations In SoapUI
Now let’s go back and look at the input to this Web Service.
var Input = {nFahrenheit:33};
Normally when you think of Web Services, you think of XML – however, Reader expects the input parameters in the form of a JavaScript object that is structurally similar to the input XML (although quite a bit simpler). The curly braces define the object, and the “nFahrenheit:33” define a single element with a value of 33.
How did I know what values to put in the curly braces? Well, again I use either Designer or SOAPUI, as shown in these screenshots:

Input Fields In Designer

Input Fields in SoapUI
You can ignore the “soapenv” (or SOAP envelope) or “Message Body”, the namespace prefix (“tem:”), and the root node (FahrenheitToCelcius) – the only important thing is the nFahrenheit input parameter.
Normally, the value would not be hard coded to a fixed number, but would come from a field in the form, so you may in fact use something like this:
var tempF = DecimalField1.rawValue;
var Input = {nFahrenheit: tempF};
Finally, we need to process the results.
xfa.host.messageBox(result);
Again, instead of giving us raw XML, Reader presents us with the data as a JavaScript object. In this case, there is only a single value returned, and this comes back as a single string value. In this case, we’ve simply displayed this value in a Message Box, although we could assign this to another field.
A Slightly More Complex Example
Let’s look at a slightly more complicated example:
try {
var cURL = "http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL";
SOAP.wireDump = false;
var service = SOAP.connect(cURL);
var Input = {sCountryISOCode:countryTextField};
var result = service.FullCountryInfo(Input);
tfCurrency.rawValue = result.sCurrencyISOCode;
tfCapital.rawValue = result.sCapitalCity;
} catch (e) {
xfa.host.messageBox("The web service could not be invoked. This may either be because you are running in Reader instead of Acrobat,"
+ " or you do not have a ReaderEnabled form, or the Web Service is unavailable.Underlying error: " + e);
}
We have changed the WSDL url to a different Web Service. The method to invoke, and the structure of the Input and results variables have all changed, but most of the code is unchanged. In this case the input comes from a field, and the results are inserted into other fields rather than simply being displayed in a dialog. You could of course do more complex processing, such as populating a drop down list.
We’ve also added some basic error handling. Remember that you can only invoke a Web Service if you are using Acrobat, or in Reader if the form has been Reader Enabled. The standard Reader behavior is to fail silently if the form is not Reader Enabled, and this control over error handling is one of the big advantages of using a programmatic model.
Mapping Inputs and Outputs
I determined the structure of inputs and outputs using Designer is shown below. Only a few of the possible output values are used, and are highlighted in red.

Designer Inputs and Outputs For Country Information
Depending on the structure of the returned XML data, Reader will construct a slightly different JavaScript object. To the best of my knowledge, this is not explicitly documented, but based on my explorations, the rules are as follows:
- All values are strings. Reader does not differentiate between different data types. Fortunately JavaScript does a good job of casting strings to other data types.
- A single return value will result in a single string contained in the “result” variable. (Like our temperature converter service.)
- Multiple return values can be accessed using JavaScript “dot” notation. For example, in the “country information” example, result contains result.sCurrencyISOCode and result.sCapitalCity and other sub-objects.
- If repeating data is encountered, it will be added as an array. So for the multiple languages in the country info, you might get something like:
result.Languages.tLanguage[0].sName; and
result.Languages.tLanguage[1].sName; etc
- You need to be a little careful – for an element which can repeat, if there is only one row of data, Reader won’t realize that the data is repeating, and will not create an array, instead just creating a single sub-element. So if there is just one row, instead of
result.Languages.tLanguage[0].sName;
you will need to use:
result.Languages.tLanguage.sName;
Similarly, if there are no rows of data, then there will be no objects. Your code will need to check whether there are zero, one or multiple objects available. To check for the existence of an element, compare it with the JavaScript “undefined” keyword.
- In some cases, the Web Service may return an error message rather than the data. Again, check for the existence of this error message by comparing against the JavaScript “undefined” keyword. For example:
if (result.some_error_element != undefined) { etc...
For the Input variables, if you need to create more than one input variable, you can simply separate them with commas. For more information on constructing and using JavaScript objects, there are many resources on the web. This is one: http://www.hunlock.com/blogs/Mastering_JSON_(_JavaScript_Object_Notation_)
Both of the Web Services referenced in this blog are real Web Services that you can use in your own experiments. However, as they are hosted by third-parties, they may or may not be available when you try them.
Note: There is a more sophisticated version of Web Service invocation using the SOAP.request(…) method call. This is documented in the AcroJSGuide.pdf file available from the Adobe web site. It’s more complicated to use than the technique shown above, and generally I’ve found that I don’t need the sophistication that it provides.
Conclusion
It’s actually quite simple to invoke Web Services from PDF SmartForms programmatically. In many cases, this is more powerful than using the visual design technique. Hopefully this blog gives you the techniques to help you do that.

Usability is King!!!
The technology also opens up opportunities for field staff to swap tasks between themselves, or bid for tasks’ real time, giving some of the power of scheduling back to the workforce. The holy grail of field worker empowerment is applications that allow staff to complete all aspects of their job without having to contact the office at all. Superior Food Services reduced sales reps calls back to the office by 20% after implementing a field mobility application.
Technology companies have been talking about the dawning of the age of the mobile worker for some time, but the reality is that it is already here. International Data Corporation (IDC) has estimated that by the end of 2010 there will be more than “1 billion mobile workers”. Devices like smartphone and tablets have become cheaper and more powerful, the user interfaces richer and the speed of mobile internet (like 3G) has become quicker, the time is now right for the wide spread adoption of Field Mobility applications.



If any of these issues resonate with you, then a Data Dictionary may help to solve your problems. A Data Dictionary allows you to define all the data items that your organization collects, and associate “meta-data” about these data items – the default label, tooltip, maximum length, field type, storage location, etc.


As someone who is new to Adobe LiveCycle, Adobe MAX offered me the opportunity to really get to know what is on the leading edge of new developments at Adobe. As an SE at Avoka Technologies this gives me the tools I need to talk about LiveCycle to potential customers, to offer consultancy services in designing great user experiences for the enterprise.
In the keynote session, Kevin Lynch (CTO Adobe) and David Nüscheler (CTO Day Software), gave a quick demonstration of how CQ5 can be used to by the business (not IT), to customise media rich websites for multiscreen. The concept is that a mobile website inherits content from the main website, but can be overridden with more effective content for different screens.