This topic is for developers who want to build web applications using FME Server Web Services API. This topic contains code for common requests with FME Server Web Services API.
This tutorial is for Java, but the same concept can be applied to other programming languages.
Please note that the sample code provided is intended for demonstration purposes only:
For demonstration purposes a sample JavaScript web application has been created to illustrate many of the common FME Web Service API concepts with sample code. The sample application must be run on the machine FME Server is hosted on. When the command line application opened in a web browser, JavaScript will render a popup containing instructions.
Note: Our demo also takes advantage of our REST API. The reason behind this will become obvious as you read on.
Web services are run on workspaces which reside in repositories. Furthermore, each workspace can be setup to have a different subset of published parameters and web services available. However, the Web Services API does not provide any means of determining the available repositories, workspaces, and their respective published parameters and services available.
Developers can either:
Of the available APIs, the REST API is the most compatible because:
Our REST API supports Working with Repositories, Working with Workspaces, and Working with Jobs. Although not listed in the REST tutorial (but included in our demo), REST can determine the available services for a given workspace. (See Working with Web Services.)
For the purpose of this tutorial, we will be using a built in XML parser in Java. First, we must import the required packages:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
Let us also create a function that can take a string and transform it to an XML document.
private Document parseXML(String contents) throws Exception
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(contents));
Document doc = db.parse(is);
return doc;
}
Listing the services available for a workspace can be done using REST and knowing the URI to the workspace (which can be generated from the repository and workspace name).
String fmeUrl = "http://"+host_+":"+port_+"/fmerest/repositories/"+repository+"/"+workspace+".xml?token="+token_;
GetMethod method = new GetMethod(fmeUrl);
client_.executeMethod(method);
String contents = method.getResponseBodyAsString();
Document doc = parseXML(contents);
NodeList nl = doc.getElementsByTagName("service");
String msg = "Services:\n";
String[] services = new String[nl.getLength()];
for (int s = 0; s < nl.getLength(); s++) {
services[s] = ((Element)nl.item(s)).getElementsByTagName("uri").item(0).getTextContent();
String serviceName = ((Element)nl.item(s)).getElementsByTagName("name").item(0).getTextContent();
msg += (s+1) + ". " + serviceName + "\n";
}
To run the web service, we can send an HTTP request to the server.
As with any other HTTP request:
// for the request to run the service
PostMethod runMethod = new PostMethod(serviceURL);
// here we can add any parameters and tm_directives
client_.executeMethod(runMethod);
Transformation Manager Directives are settings that can be applied to all services. These settings range in complexity from adding a description to scheduling the service to run at a later date. For more information, see Transformation Manager.
For our example, we set a high value for the priority of this job, in order to tell the FME Server to execute it before other tasks. This is not necessary but just done to illustrate how to set directives.
method.addParameter("tm_priority","80");
Through REST, we can easily obtain a list of published parameters and their respective input types.
// for the request to run the service
String runUrl = serviceURL;
PostMethod runMethod = new PostMethod(runUrl);
NodeList nl_parameters = doc.getElementsByTagName("parameter");
// get value for each parameter
for (int s = 0; s < nl_parameters.getLength(); s++)
{
Element el = (Element)nl_parameters.item(s);
String name = el.getElementsByTagName("name").item(0).getTextContent();
String display = el.getElementsByTagName("description").item(0).getTextContent();
String defaultValue = el.getElementsByTagName("defaultValue").item(0).getTextContent();
String optionsType = el.getElementsByTagName("optionsType").item(0).getTextContent();
if (optionsType.equals("SINGLECHOICE_CONFIG")) {
// single choice, so choose it
NodeList nl_options = el.getElementsByTagName("option");
String msg = display + "\n";
String[] options = new String[nl_options.getLength()];
for (int i = 0; i < nl_options.getLength(); i++) {
options[i] = ((Element)nl_options.item(i)).getElementsByTagName("value").item(0).getTextContent();
msg += (i+1) + ". " + options[i] + "\n";
}
String selected = getInput(msg + "Please select the number (default = "+defaultValue+"):");
if (selected == "") {
runMethod.addParameter(name, defaultValue);
} else {
//parameters.put(name, options[Integer.parseInt(selected)-1]);
runMethod.addParameter(name, options[Integer.parseInt(selected)-1]);
}
} else if (optionsType.equals("MULTICHOICE_CONFIG")) {
// prompt the user for each choice
NodeList nl_options = el.getElementsByTagName("option");
System.out.println(display + "(Multiple options, enter 'Y'/'N' or return for the default value.)");
for (int i = 0; i < nl_options.getLength(); i++) {
String value = ((Element)nl_options.item(i)).getElementsByTagName("value").item(0).getTextContent();
String choice = getInput(value + " (default = '" + (value.equals(defaultValue) ? "Y" : "N") + "') ?");
// add the choice if the user specified "Y" or the default choice was selected (and was "Yes")
if (choice.equals("Y") || choice.equals("y") ||
(choice.equals("") && defaultValue.equals(value))) {
runMethod.addParameter(name+"[]", value);
}
}
} else {
// for everything else, default to a text input
String value = getInput(display + "(default = '" + defaultValue + "') ");
// use default if nothing provided
if (value == "") {
value = defaultValue;
}
//parameters.put(name, value);
runMethod.addParameter(name, value);
}
}
The format received will vary depending on the service used. XML, json, and html can be parsed and/or displayed. Any other format should be saved or run in another application (ie. Google Earth for .kmz files).
String contentType = runMethod.getResponseHeader("Content-Type").getValue();
if (contentType.contains("text/xml") || contentType.contains("text/html") || contentType.contains("text/json"))
{
// print this out to the user
String runContents = runMethod.getResponseBodyAsString();
System.out.println(runContents);
}
else
{
// we had best download this file to a location
String filePath = getInput("Please enter the location you would like to save this file to: ");
FileOutputStream file = new FileOutputStream(filePath);
PrintStream fileStream = new PrintStream(file);
if (client_.executeMethod(method) != 200)
{
throw new Exception("Getting workspace failed");
}
byte[] responseBody = method.getResponseBody();
// Deal with the response.
// Use caution: ensure correct character encoding and is not binary data
fileStream.println(new String(responseBody));
fileStream.close();
file.close();
}