Requirements

Prerequisite knowledge

Intermediate Java/Flex programmer

User level

Beginning

You can extend LiveCycle ES2 functionality by creating a custom component that invokes an external web service. That is, you can create a LiveCycle ES2 service that returns third-party web service data. The service can be used in business processes that you create using Workbench ES2. For example, assume that you create a business process for a government department that tracks weather information. You can create a LiveCycle ES2 service that invokes a third-party web service and returns weather information.

Users of the new LiveCycle ES2 service can invoke its operations like other LiveCycle ES2 service operations. A user does not have to specify a WSDL endpoint, construct an XML SOAP request, or handle an XML SOAP response. In fact, a user does not have to know that the service is invoking an external web service. It is the component, not the user that handles the underlying SOAP requests and SOAP responses.

The following illustration shows a custom component located in the LiveCycle ES2 service container invoking a third-party web service.

Because a custom component is written using Java, you can use Java proxy classes created using JAX-WS or AXIS within the component. You can use a tool such as AXIS to generate Java classes that are based on the WSDL of an external web service. Then you can use these Java proxy classes within your custom component.

To demonstrate how to create a component that invokes an external web service, the component created in this article invokes a web service that returns weather information. For the reminder of this article, the component is called the weather component. The WSDL of the web service that returns weather information is as follows:

http://ws.cdyne.com/WeatherWS/Weather.asmx?wsdl

The custom component creates a service named WeatherService and exposes the following two operations:

The following XML is an example of the data that the GetWeather operation returns:

<transaction> <header> <txtDescription>Cloudy</txtDescription> <txtCity>San Jose</txtCity> <txtState>CA</txtState> <txtWind>CALM</txtWind> <txtHumidity>90</txtHumidity> <txtDate0>2009-09-24</txtDate0> <txtDayHigh0>101</txtDayHigh0> <txtDayLow0/> <txtPop0>00</txtPop0> <txtDate1>2009-09-25</txtDate1> <txtDayHigh1>99</txtDayHigh1> <txtDayLow1>65</txtDayLow1> <txtPop1>00</txtPop1> <txtDate2>2009-09-26</txtDate2> <txtDayHigh2>101</txtDayHigh2> <txtDayLow2>65</txtDayLow2> <txtPop2>00</txtPop2> <txtDate3>2009-09-27</txtDate3> <txtDayHigh3>94</txtDayHigh3> <txtDayLow3>64</txtDayLow3> <txtPop3>00</txtPop3> <txtDate4>2009-09-28</txtDate4> <txtDayHigh4>88</txtDayHigh4> <txtDayLow4>64</txtDayLow4> <txtPop4>00</txtPop4> <txtDate5>2009-09-29</txtDate5> <txtDayHigh5>81</txtDayHigh5> <txtDayLow5>64</txtDayLow5> <txtPop5>00</txtPop5> <txtDate6>2009-09-30</txtDate6> <txtDayHigh6>80</txtDayHigh6> <txtDayLow6>59</txtDayLow6> <txtPop6>00</txtPop6> </header> </transaction>

The following illustration shows the property editor in Workbench ES2 that corresponds to the GetCity operation. Notice that the operation accepts an input string value. In this example, the ZIP code is 95101, which is the ZIP code for San Jose, California. The return value is written to a string process variable named outVal.

When a user invokes the GetCity operation, they do not have to specify a WSDL endpoint or create an XML SOAP request. All the user has to do is drag the operation on a process map in Workbench ES2 and specify the input value. It is not necessary for the user to know that the information is really coming from an external web service.

For more information about creating components, see Programming with LiveCycle ES2.

Summary of steps

To develop a component that invokes an external web service, perform the following steps:

  1. Create Java proxy classes that consume the soap stack of the external web service.
  2. Create your application logic.
  3. Define the component XML file.
  4. Deploy the component to LiveCycle ES2.
  5. Test the component by creating an AIR application that invokes the WeatherSerice.

Note: You can test your component using different methods. This development article creates an AIR application that invokes the weather service. For information on different ways in which you can programmatically interact with a LiveCycle ES2 service, see Programming with LiveCycle ES2.

Creating Java proxy classes using Axis

You can use the Apache Axis WSDL2Java tool to convert the third-party WSDL into Java proxy classes. These classes enable you to invoke operations that belong to the third-party web service. Using Apache Ant, you can generate JAVA files from a service WSDL. You can download Apache Axis at the following URL http://ws.apache.org/axis/.

You can generate Java library files by performing the following steps:

  1. Install Apache Ant on the client computer. It is available at http://ant.apache.org/bindownload.cgi.
  2. Add the bin directory to your class path.
  3. Set the ANT_HOME environment variable to the directory where you installed Ant.
  4. Install Apache Axis 1.4 on the client computer. It is available at http://ws.apache.org/axis/.
  5. Set up the class path to use the Axis JAR files in your web service client, as described in the Axis installation instructions at http://ws.apache.org/axis/java/install.html.
  6. Use the Apache WSDL2Java tool in Axis to generate Java proxy classes. Create an Ant build script to accomplish this task. The following script is a sample Ant build script named build.xml:
<?xml version="1.0"?> <project name="axis-wsdl2java"> <path id="axis.classpath"> <fileset dir="C:\axis-1_4\lib" > <include name="**/*.jar" /> </fileset> </path> <taskdef resource="axis-tasks.properties" classpathref="axis.classpath" /> <target name="output-wsdl2java-client" description="task"> <axis-wsdl2java output="C:\JavaFiles" testcase="false" serverside="false" verbose="true" url="http://ws.cdyne.com/WeatherWS/Weather.asmx?wsdl" > </axis-wsdl2java> </target> </project>
  1. Create a BAT file to execute the Ant build script. The following command can be located within a BAT file that is responsible for executing the Ant build script:
ant -buildfile "build.xml" output-wsdl2java-client

The JAVA files are written to the C:\JavaFiles folder as specified by the output property.          

  1. Package the JAVA proxy files into a JAR file. This JAR file must be used within the Java project used to create the custom component. In addition, the following JAR files must also be included in the Java project’s class path:
  • activation.jar
  • axis.jar
  • commons-codec-1.3.jar
  • commons-collections-3.1.jar
  • commons-discovery.jar
  • commons-logging.jar
  • dom3-xml-apis-2.5.0.jar
  • jai_imageio.jar
  • jaxen-1.1-beta-9.jar
  • jaxrpc.jar
  • log4j.jar
  • mail.jar
  • saaj.jar
  • wsdl4j.jar
  • xalan.jar
  • xbean.jar
  • xercesImpl.jar

These JAR files are in the <install directory>/Adobe/Adobe LiveCycle ES2/LiveCycle_ES_SDK/client-libs/thirdparty.

Creating application logic for the weather component

To create the weather component, perform the following tasks:

  1. Define the service interface.
  2. Define the service implementation.

Note: This development article does not discuss how to create a LiveCycle ES2 implementation or Bootstrap implementation. For information about creating these classes, see “Creating Your First Component” in Programming with LiveCycle ES2.

Defining the service interface

A service implementation is essentially a Plain Old Java Object (POJO) that you can develop by creating a Java interface. This interface defines the service’s operations (public methods), input values, and return values. The public methods that are defined within the Java interface become operations that the service exposes.

The weather component exposes two operations named GetCity and GetWeather that is defined in the component interface. The following example shows the WeatherInformation interface.

package com.adobe.idp.sample; public interface WeatherInformation { public String GetCity(String zip); public org.w3c.dom.Document GetWeather(String zip); }

The WeatherInformation interface belongs to a package named com.adobe.idp.sample. The implementation class that is required to create the weather component is added to this package.

Defining the service implementation

Create a service implementation class that implements the WeatherInformation interface. A service implementation must conform to the following restrictions:

  • The implementation class must have a public no-argument constructor.
  • The service implementation class must be stateless.
  • Input parameters, output parameters, and exceptions must be serializable.

The business logic that LiveCycle ES2 executes when the operation is invoked is located in the corresponding method. For example, consider the GetWeather method that is defined in the WeatherInformation interface. Create business logic within the GetWeather method that invokes the third-party web service and retrieve weather information. Weather information is returned within XML data.

To invoke the third-party web service, you use Java classes that belong to the package com.cdyne.ws.WeatherWS.*. To use these classes, include the JAR file that contains JAVA proxy classes in the Java project’s class path. The following code fragment shows how to create a com.cdyne.ws.WeatherWS.ForecastReturn instance. You use this instance to retrieve weather information.

WeatherLocator sl = new WeatherLocator(); WeatherSoap weatherOb = sl.getWeatherSoap(); com.cdyne.ws.WeatherWS.ForecastReturn forecast = weatherOb.getCityForecastByZIP(zip);

After weather information is retrieved, it is placed in an XML document that is created during run-time. Use org.w3c.dom.* Java classes to create the XML document. The GetWeather method returns the XML as its return type. A user-defined method named CreateXMLDatasouce creates the XML document that contains the weather information.

Example: Defining the WeatherInformationImpl class
package com.adobe.idp.sample; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Element; import com.cdyne.ws.WeatherWS.*; public class WeatherInformationImpl implements WeatherInformation { public String GetCity(String zip) { String myCity=""; try{ //This method returns the city that corresponds to the ZIP value WeatherLocator sl = new WeatherLocator(); WeatherSoap weatherOb = sl.getWeatherSoap(); com.cdyne.ws.WeatherWS.WeatherReturn weatherReturn = weatherOb.getCityWeatherByZIP(zip); myCity = weatherReturn.getCity(); return myCity ; }catch (Exception e) { System.out.println("The following error occurred during this operation " +e.getMessage()); } return null; } /** * This operation returns weather information in an XML document */ public org.w3c.dom.Document GetWeather(String zip) { org.w3c.dom.Document myXML = null; try{ WeatherLocator sl = new WeatherLocator(); WeatherSoap weatherOb = sl.getWeatherSoap(); //Create the Forecast objects com.cdyne.ws.WeatherWS.ForecastReturn forecast = weatherOb.getCityForecastByZIP(zip); com.cdyne.ws.WeatherWS.WeatherReturn weatherReturn = weatherOb.getCityWeatherByZIP(zip); //Get Weather return information String description = weatherReturn.getDescription(); String myCity = weatherReturn.getCity(); String myWind = weatherReturn.getWind(); String myState = weatherReturn.getState(); String myHumidity = weatherReturn.getRelativeHumidity(); //Create an array of WeatherInformationData objects WeatherInformationData[] myWeatherArrays = new WeatherInformationData[7]; //Get Forecast object Forecast[] myForecasts = forecast.getForecastResult(); int len = myForecasts.length; //7 for the seven day forecast for (int z=0;z<len;z++) { //Create a WeatherInformation object to store the values WeatherInformationData wi = new WeatherInformationData(); //Loop through the forecasts Forecast singleForecast = (Forecast)myForecasts[z]; //Calendar theDate = singleForecast.getDate(); Calendar theDate= Calendar.getInstance(); POP myPop = singleForecast.getProbabilityOfPrecipiation(); String dayChanceofRain = myPop.getDaytime(); Temp myTemp = singleForecast.getTemperatures(); String dayHigh = myTemp.getDaytimeHigh(); String dayLow = myTemp.getMorningLow(); Calendar c = Calendar.getInstance(); int day = c.get(Calendar.DATE); int month = c.get(Calendar.MONTH) + 1; int year = c.get(Calendar.YEAR); String myYear = Integer.toString(year); String myMonth = Integer.toString(month); String myDay = Integer.toString(day); String dt = myYear+"-"+myMonth+"-"+myDay; // Start date SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); c.setTime(sdf.parse(dt)); c.add(Calendar.DATE, z); // number of days to add dt = sdf.format(c.getTime()); // dt is now the new date //Put this information into an XML document wi.SetDate(dt); wi.SetDayHigh(dayHigh); wi.SetDayLow(dayLow); wi.SetPop(dayChanceofRain); myWeatherArrays[z]=wi; } //Get the XML document that contains the weather information myXML = CreateXMLDatasouce(myWeatherArrays,description, myCity,myWind,myState,myHumidity); return myXML; }catch (Exception e) { System.out.println("The following error occurred during this operation " +e.getMessage()); } return null; } //Create an XML data source private static org.w3c.dom.Document CreateXMLDatasouce(WeatherInformationData[] myWeatherArrays, String description,String myCity,String myWind,String myState,String myHumidity) { try { //Build the XML data //Create DocumentBuilderFactory and DocumentBuilder objects DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); //Create a new Document object org.w3c.dom.Document document = builder.newDocument(); //Create the root element and append it to the XML DOM Element root = (Element)document.createElement("transaction"); document.appendChild(root); //Create a header element Element rec = (Element)document.createElement("header"); root.appendChild(rec); // 1 -- Create the txtDescription element Element txtDescription = (Element)document.createElement("txtDescription"); txtDescription.appendChild(document.createTextNode(description)); rec.appendChild(txtDescription); // 2 -- Create the txtCity element Element txtCity = (Element)document.createElement("txtCity"); txtCity.appendChild(document.createTextNode(myCity)); rec.appendChild(txtCity); // 3 -- Create the txtState element Element txtState = (Element)document.createElement("txtState"); txtState.appendChild(document.createTextNode(myState)); rec.appendChild(txtState); // 4 -- Create the txtWind element Element txtWind = (Element)document.createElement("txtWind"); txtWind.appendChild(document.createTextNode(myWind)); rec.appendChild(txtWind); // 5-- Create the txtHumidity element Element txtHumidity = (Element)document.createElement("txtHumidity"); txtHumidity.appendChild(document.createTextNode(myHumidity)); rec.appendChild(txtHumidity); int count = 7; //Loop through for the 7 weather objects for (int in=0;in<count;in++){ //Get the Weather elements WeatherInformationData wi =myWeatherArrays[in]; //Get each field and place it in the XML document String dt = wi.GetDate(); String dayHigh = wi.GetDayHigh(); String dayLow = wi.GetDayLow(); String dayChanceofRain = wi.GetPop(); String myDateName = "txtDate"+in ; String myDayHighName = "txtDayHigh"+in ; String myDayLowName = "txtDayLow"+in ; String myPopName = "txtPop"+in ; //Set the Date information Element txtDate = (Element)document.createElement(myDateName); txtDate.appendChild(document.createTextNode(dt)); rec.appendChild(txtDate); //Set the dayHigh information Element txtDayHigh = (Element)document.createElement(myDayHighName); txtDayHigh.appendChild(document.createTextNode(dayHigh)); rec.appendChild(txtDayHigh); //Set the Date information Element txtDayLow = (Element)document.createElement(myDayLowName); txtDayLow.appendChild(document.createTextNode(dayLow)); rec.appendChild(txtDayLow); //Set the Date information Element txtPop= (Element)document.createElement(myPopName); txtPop.appendChild(document.createTextNode(dayChanceofRain)); rec.appendChild(txtPop); } //Return the new XML data return document; } catch (Exception ee) { ee.printStackTrace(); } return null; } }

Adding the WeatherInformationData class

A WeatherInformationData object is used to store weather information. Values from this class are written to the XML document. Add the WeatherInformationData class to your Java project. The following code represents this class.

Example: Defining the WeatherInformationData class

package com.adobe.idp.sample; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Element; import com.cdyne.ws.WeatherWS.*; public class WeatherInformationImpl implements WeatherInformation { public String GetCity(String zip) { String myCity=""; try{ //This method returns the city that corresponds to the ZIP value WeatherLocator sl = new WeatherLocator(); WeatherSoap weatherOb = sl.getWeatherSoap(); com.cdyne.ws.WeatherWS.WeatherReturn weatherReturn = weatherOb.getCityWeatherByZIP(zip); myCity = weatherReturn.getCity(); return myCity ; }catch (Exception e) { System.out.println("The following error occurred during this operation " +e.getMessage()); } return null; } /** * This operation returns weather information in an XML document */ public org.w3c.dom.Document GetWeather(String zip) { org.w3c.dom.Document myXML = null; try{ WeatherLocator sl = new WeatherLocator(); WeatherSoap weatherOb = sl.getWeatherSoap(); //Create the Forecast objects com.cdyne.ws.WeatherWS.ForecastReturn forecast = weatherOb.getCityForecastByZIP(zip); com.cdyne.ws.WeatherWS.WeatherReturn weatherReturn = weatherOb.getCityWeatherByZIP(zip); //Get Weather return information String description = weatherReturn.getDescription(); String myCity = weatherReturn.getCity(); String myWind = weatherReturn.getWind(); String myState = weatherReturn.getState(); String myHumidity = weatherReturn.getRelativeHumidity(); //Create an array of WeatherInformationData objects WeatherInformationData[] myWeatherArrays = new WeatherInformationData[7]; //Get Forecast object Forecast[] myForecasts = forecast.getForecastResult(); int len = myForecasts.length; //7 for the seven day forecast for (int z=0;z<len;z++) { //Create a WeatherInformation object to store the values WeatherInformationData wi = new WeatherInformationData(); //Loop through the forecasts Forecast singleForecast = (Forecast)myForecasts[z]; //Calendar theDate = singleForecast.getDate(); Calendar theDate= Calendar.getInstance(); POP myPop = singleForecast.getProbabilityOfPrecipiation(); String dayChanceofRain = myPop.getDaytime(); Temp myTemp = singleForecast.getTemperatures(); String dayHigh = myTemp.getDaytimeHigh(); String dayLow = myTemp.getMorningLow(); Calendar c = Calendar.getInstance(); int day = c.get(Calendar.DATE); int month = c.get(Calendar.MONTH) + 1; int year = c.get(Calendar.YEAR); String myYear = Integer.toString(year); String myMonth = Integer.toString(month); String myDay = Integer.toString(day); String dt = myYear+"-"+myMonth+"-"+myDay; // Start date SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); c.setTime(sdf.parse(dt)); c.add(Calendar.DATE, z); // number of days to add dt = sdf.format(c.getTime()); // dt is now the new date //Put this information into an XML document wi.SetDate(dt); wi.SetDayHigh(dayHigh); wi.SetDayLow(dayLow); wi.SetPop(dayChanceofRain); myWeatherArrays[z]=wi; } //Get the XML document that contains the weather information myXML = CreateXMLDatasouce(myWeatherArrays,description, myCity,myWind,myState,myHumidity); return myXML; }catch (Exception e) { System.out.println("The following error occurred during this operation " +e.getMessage()); } return null; } //Create an XML data source private static org.w3c.dom.Document CreateXMLDatasouce(WeatherInformationData[] myWeatherArrays, String description,String myCity,String myWind,String myState,String myHumidity) { try { //Build the XML data //Create DocumentBuilderFactory and DocumentBuilder objects DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); //Create a new Document object org.w3c.dom.Document document = builder.newDocument(); //Create the root element and append it to the XML DOM Element root = (Element)document.createElement("transaction"); document.appendChild(root); //Create a header element Element rec = (Element)document.createElement("header"); root.appendChild(rec); // 1 -- Create the txtDescription element Element txtDescription = (Element)document.createElement("txtDescription"); txtDescription.appendChild(document.createTextNode(description)); rec.appendChild(txtDescription); // 2 -- Create the txtCity element Element txtCity = (Element)document.createElement("txtCity"); txtCity.appendChild(document.createTextNode(myCity)); rec.appendChild(txtCity); // 3 -- Create the txtState element Element txtState = (Element)document.createElement("txtState"); txtState.appendChild(document.createTextNode(myState)); rec.appendChild(txtState); // 4 -- Create the txtWind element Element txtWind = (Element)document.createElement("txtWind"); txtWind.appendChild(document.createTextNode(myWind)); rec.appendChild(txtWind); // 5-- Create the txtHumidity element Element txtHumidity = (Element)document.createElement("txtHumidity"); txtHumidity.appendChild(document.createTextNode(myHumidity)); rec.appendChild(txtHumidity); int count = 7; //Loop through for the 7 weather objects for (int in=0;in<count;in++){ //Get the Weather elements WeatherInformationData wi =myWeatherArrays[in]; //Get each field and place it in the XML document String dt = wi.GetDate(); String dayHigh = wi.GetDayHigh(); String dayLow = wi.GetDayLow(); String dayChanceofRain = wi.GetPop(); String myDateName = "txtDate"+in ; String myDayHighName = "txtDayHigh"+in ; String myDayLowName = "txtDayLow"+in ; String myPopName = "txtPop"+in ; //Set the Date information Element txtDate = (Element)document.createElement(myDateName); txtDate.appendChild(document.createTextNode(dt)); rec.appendChild(txtDate); //Set the dayHigh information Element txtDayHigh = (Element)document.createElement(myDayHighName); txtDayHigh.appendChild(document.createTextNode(dayHigh)); rec.appendChild(txtDayHigh); //Set the Date information Element txtDayLow = (Element)document.createElement(myDayLowName); txtDayLow.appendChild(document.createTextNode(dayLow)); rec.appendChild(txtDayLow); //Set the Date information Element txtPop= (Element)document.createElement(myPopName); txtPop.appendChild(document.createTextNode(dayChanceofRain)); rec.appendChild(txtPop); } //Return the new XML data return document; } catch (Exception ee) { ee.printStackTrace(); } return null; } }

Defining the component XML file

Create a component XML file to deploy a component to LiveCycle ES. A component XML file exists for each component and provides metadata about the component. You can use the component XML file to customize your component to meet your requirements. For example, you can specify an icon that is visible to Workbench ES users who build processes using the component.

Note: For more information about the component XML file, see Adobe LiveCycle ES2 Component XML Reference.

The following component.xml file is used for the weather component. Notice that all JAR files required by the component are specified in the class-path element.

Example: Defining the component XML file for the weather component
<component xmlns="http://adobe.com/idp/dsc/component/document"> <!-- Unique id identifying this component --> <component-id>com.adobe.livecycle.sample2.weatherSampleComponent</component-id> <!-- Version --> <version>1.0</version> <class-path>Weather.jar activation.jar axis.jar commons-codec-1.3.jar commons-collections-3.1.jar commons-discovery.jar commons-logging.jar dom3-xml-apis-2.5.0.jar jaxb-api.jar jaxb-impl.jar jaxb-libs.jar jaxb-xjc.jar jaxen-1.1.1.jar jaxrpc.jar log4j.jar mail.jar namespace.jar relaxngDatatype.jar saaj.jar serializer.jar wsdl4j.jar xalan.jar xbean.jar xercesImpl.jar xsdlib.jar</class-path> <services> <!-- Unique name for service descriptor. The value is used as the default name for deployed services --> <service name="WeatherService"> <!-- service implementation class definition --> <implementation-class>com.adobe.idp.sample.WeatherInformationImpl</implementation-class> <!-- description --> <description>Allows you to obtain weather information based on a zip code.</description> <operations> <!-- method name in the interface setSmtpHost--> <operation name="GetCity"> <!-- input parameters to the "send" method --> <input-parameter name="zip" title="zip" type="java.lang.String"> </input-parameter> <output-parameter name="City" type="java.lang.String"> </output-parameter> <faults> <fault name="MessagingException" type="javax.mail.MessagingException"/> <fault name="Exception" type="java.lang.Exception"/> </faults> </operation> <operation name="GetWeather"> <!-- input parameters to the "send" method --> <input-parameter name="zip" title="zip" type="java.lang.String"> </input-parameter> <output-parameter name="Report" title="Report" type="org.w3c.dom.Document"> </output-parameter> <faults> <fault name="MessagingException" type="javax.mail.MessagingException"/> <fault name="Exception" type="java.lang.Exception"/> </faults> </operation> </operations> </service> </services> </component>

Deploying your component

To deploy the component to LiveCycle ES2, you package your Eclipse project into a JAR file. Ensure that external JAR files that the component’s business logic depends on are also included in the component JAR file. As well, the component XML file must be present. The component.xml file and external JAR files must be located at the root of the JAR file.

In the previous diagram, the Weather.JAR file represents the Java proxy classes that were created using Apache AXIS. (See Creating Java proxy classes using Axis.)

It is recommended that you include only the JAR files that are required to run the Java application logic located in your component. That is, if your component does not require an external JAR file, do not include it in the component JAR file.

To deploy a component:

  1. Start Workbench ES2.
  2. Log in to Workbench ES.
  3. Select Window > Show Views > Components. This action adds the Components view to Workbench ES.
  4. Right-click the Components icon and select Install Component.
  5. Select the component JAR file through the file browser and click Open.
  6. Select Service Descriptors, and right-click and select Activate Service.
  7. Right-click on your component and select Start Component. A green arrow appears next to the name if it succeeds.

Note: You can also programmatically deploy a component instead of using Workbench ES. (See Programmatically Deploying Components in Programming with LiveCycle ES2.)

Invoking the Weather Service

After you deploy the weather component, you can invoke it like other LiveCycle ES2 services. For example, you can create an AIR application that invokes the service. The following illustration shows an AIR application displaying weather information. The AIR application invokes the weather service using LiveCycle Remoting. Notice that input in the application is a US ZIP code.

Note: For information about LiveCycle Remoting, see Invoking LiveCycle ES2 Using LiveCycle Remoting in Programming with LiveCycle ES2.

To invoke the weather service, create a Remote object instance in your AIR project. Also specify the opeation that you want to invoke.

<mx:RemoteObject id="WeatherServiceOb" destination="WeatherService" result="resultHandler(event);"> <mx:method name="GetWeather" result="handleReturn(event)"/> </mx:RemoteObject>

In this situation, the name of the object is WeatherServiceOb. The operation that is invoked is GetWeather. This operation requires a string value that represents a ZIP code and returns XML that contains weather information. The AIR application retrieves the XML returned by the GetWeather operation and parses it. The user-defined method that parses the XML document in the following code is named GetNodeValue.

The following code represents the application logic for the AIR application.

Example: An AIR application invoking the custom Weather Service

<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="/2006/mxml" layout="absolute"> <mx:Style source="../WeatherAppCSS.css"/> <mx:Script> <![CDATA[ import mx.events.ItemClickEvent; import mx.rpc.events.ResultEvent; import mx.rpc.livecycle.DocumentReference; import flash.net.FileReference; import flash.net.URLRequest; import flash.events.Event; import flash.events.DataEvent; import mx.messaging.ChannelSet; import mx.messaging.channels.AMFChannel; import mx.collections.ArrayCollection; import mx.collections.Sort; import mx.collections.ICollectionView ; import mx.collections.SortField; import mx.rpc.AsyncToken; import mx.formatters.NumberFormatter; import mx.managers.CursorManager; import mx.controls.Alert; import mx.states.Transition; import mx.events.CloseEvent; //Set up the icons [Embed(source="icons/Cloudy.png")] [Bindable] public var iconCloudy:Class; [Embed(source="icons/partyCloud.png")] [Bindable] public var iconPartialCloudy:Class; [Embed(source="icons/rain.png")] [Bindable] public var iconRain:Class; [Embed(source="icons/Sunny.png")] [Bindable] public var iconSunny:Class; private var serverPort:String = "hiro-xp.can.adobe.com:8080"; private function resultHandler(event:ResultEvent):void { } private function handleReturn(event:ResultEvent):void { var token:AsyncToken = event.token; var res:Object = event.result; var myReport:XML = res["Report"] as XML; //Get the values from the returned XML docucment var myCity:String = GetNodeValue("txtCity",myReport); var myState:String = GetNodeValue("txtState",myReport); var myDescription:String = GetNodeValue("txtDescription",myReport); var myWind:String = GetNodeValue("txtWind",myReport); var myHigh:String = GetNodeValue("txtDayHigh0",myReport); var myLow:String = GetNodeValue("txtDayLow0",myReport); var myPop:String = GetNodeValue("txtPop0",myReport); var pop1:String = myPop+"%"; var myHumidity:String = GetNodeValue("txtHumidity",myReport); var myDate:String = GetNodeValue("txtDate0",myReport); //Set the fields in the AIR form txtCity.text = myCity; txtState.text = myState; txtDescription.text = myDescription; txtWind.text=myWind; txtHigh.text =myHigh; txtLow.text = myLow; txtPOP.text = pop1; txtHumidity.text = myHumidity; txtDate0.text = myDate; //Set weather icon var cloud:Class = iconCloudy ; var partCloud:Class = iconPartialCloudy ; var rain:Class = iconRain ; var sun:Class = iconSunny ; //Create expressions to set weather icons switch (myDescription) { case "Cloudy": cityIcon.source = cloud; break ; case "Mainly Cloudy": cityIcon.source = cloud; break ; case "Partly Cloudy": cityIcon.source = partCloud; break ; case "Sunny": cityIcon.source = sun; break ; case "Fair": cityIcon.source = sun; break ; case "Partly Sunny": cityIcon.source = partCloud; break ; case "Mainly Sunny": cityIcon.source = sun; break ; case "Mostly Sunny": cityIcon.source = sun; break ; case "Partly Sunny": cityIcon.source = partCloud; break ; case "Clear": cityIcon.source = sun; break ; case "Showers": cityIcon.source = rain; break ; case "Moderate Showers": cityIcon.source = rain; break ; case "Isolated Showers": cityIcon.source = rain; break ; case "Rain": cityIcon.source = rain; break ; case "Light Rain": cityIcon.source = rain; break ; case "Heavy Rain": cityIcon.source = rain; break ; default: cityIcon.source = partCloud; } //Set the cursor to busy CursorManager.removeBusyCursor(); } private function GetNodeValue(nodeName:String,myXML:XML):String { var name:String = nodeName ; var myList:XMLList = myXML.children(); var myList2:XMLList = myList.children(); var ee:String ="" ; for each (var element:XML in myList2) { if (element.name() == name) { ee = element.toString(); return ee; } } return ""; } private function getCity():void { //Invoke the Weather service var cs:ChannelSet= new ChannelSet(); cs.addChannel(new AMFChannel("remoting-amf", "http://" + serverPort + "/remoting/messagebroker/amf")); WeatherServiceOb.setCredentials("administrator", "password"); WeatherServiceOb.channelSet = cs; var myZip:String = txtBoxZip.text; var params:Object = new Object(); params["zip"]=myZip; var token:AsyncToken; token = WeatherServiceOb.GetWeather(params); //Set the cursor to busy CursorManager.setBusyCursor(); token.name = name; } ]]> </mx:Script> <mx:RemoteObject id="WeatherServiceOb" destination="WeatherService" result="resultHandler(event);"> <mx:method name="GetWeather" result="handleReturn(event)"/> </mx:RemoteObject> <mx:Grid x="458" y="75"> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="Enter a US ZIP code:" fontSize="16" fontWeight="bold"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:TextInput styleName="textField" id="txtBoxZip"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Button label="Get Weather" click="getCity()"/> </mx:GridItem> </mx:GridRow> </mx:Grid> <mx:Grid x="458" y="128"> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="Date:" fontSize="15" fontWeight="bold"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Text fontSize="15" fontWeight="bold" id="txtDate0"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Image id="cityIcon"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="City" fontSize="20"/> </mx:GridItem> <mx:GridItem width="100%" height="100%" fontSize="12" fontWeight="bold"> <mx:Text id="txtCity" fontSize="15"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="State:" fontSize="20"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Text id="txtState" fontSize="15" fontWeight="bold"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="Description:" fontSize="20"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Text id="txtDescription" fontSize="15" fontWeight="bold"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="Wind:" fontSize="20"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Text id="txtWind" fontSize="15" fontWeight="bold"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="High:" fontSize="20"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Text id="txtHigh" fontSize="15" fontWeight="bold"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="Low:" fontSize="20"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Text fontSize="15" id="txtLow" fontWeight="bold"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="POP:" fontSize="20"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Text fontSize="15" id="txtPOP" fontWeight="bold"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> <mx:Text text="Humidity" fontSize="19"/> </mx:GridItem> <mx:GridItem width="100%" height="100%"> <mx:Text id="txtHumidity" fontSize="15" fontWeight="bold"/> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> </mx:GridItem> <mx:GridItem width="100%" height="100%"> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> </mx:GridItem> <mx:GridItem width="100%" height="100%"> </mx:GridItem> </mx:GridRow> <mx:GridRow width="100%" height="100%"> <mx:GridItem width="100%" height="100%"> </mx:GridItem> <mx:GridItem width="100%" height="100%"> </mx:GridItem> </mx:GridRow> </mx:Grid> </mx:WindowedApplication>

This AIR application uses four PNG grpahic files: Cloudy.png, partyCloud.png, rain.png, and Sunny.png. The graphics that you use in your project can be located in a folder named icons. Place this folder in your project’s src folder.

Style sheet

This code example contains a style sheet named weather.css. The following code represents the style sheet that is used.

/* CSS file */ global { backgroundGradientAlphas: 1.0, 1.0; backgroundGradientColors: #525152,#525152; borderColor: #424444; verticalAlign: middle; color: #FFFFFF; ''> font-weight:normal; } ApplicationControlBar { fillAlphas: 1.0, 1.0; fillColors: #393839, #393839; } .textField { backgroundColor: #393839; background-disabled-color: #636563; } .button { fillColors: #636563, #424242; } .dropdownMenu { backgroundColor: #DDDDDD; fillColors: #636563, #393839; alternatingItemColors: #888888, #999999; } .questionLabel { } ToolTip { backgroundColor: black; backgroundAlpha: 1.0; cornerRadius: 0; color: white; } DateChooser { cornerRadius: 0; /* pixels */ headerColors: black, black; borderColor: black; themeColor: black; todayColor: red; todayStyleName: myTodayStyleName; headerStyleName: myHeaderStyleName; weekDayStyleName: myWeekDayStyleName; dropShadowEnabled: true; } .myTodayStyleName { color: white; } .myWeekDayStyleName { fontWeight: normal; } .myHeaderStyleName { color: red; fontSize: 16; fontWeight: bold; }

Where to go from here

For more information about creating LiveCycle ES2 components, see Programming with LiveCycle ES2.