1/20/2009
I was able to get a Flex client to invoke my first Web Service. I found that on the server side, a Web Service is trivial to code and deploy in a GlassFish server from Eclipse – a welcome relief from the complex BlazeDS configurations we’ve been dealing with. To make an existing class into a Web Service, only a @WebService annotation is needed. On the client side, the invoking code is pretty straightforward – just setting up a few listeners for response and faults. I observed that the Web Service call time (from a client on the same local network as the server, but a different machine) consistently has a pretty even distribution between 15 and 65 milliseconds.
This guide details steps in Ubuntu Linux for creating an end to end system with a Flex web GUI which invokes a Web Service in a Glassfish server. The steps are as follows, assuming a fresh Ubuntu:
- Install OpenJDK, Eclipse, and GlassFish
- Configure Eclipse for GlassFish
- Write, deploy, and test an “Echo” Web Service
- Install FlexBuilder Linux Alpha
- Write the “Echo” client
Install OpenJDK, Eclipse, and GlassFish
Install OpenJDK and Eclipse
Install GlassFish
Configure Eclipse for GlassFish
In Eclipse:
New -> Project -> Web -> Dynamic Web Project -> Next ->
under “Target Runtime” -> New… -> click “download additional server adapters” ->
select “GlassFish Java EE 5 Server” -> Next -> accept the terms, Finish -> OK -> Yes, restart now
New -> Dynamic Web Project -> Next ->
Name:EchoService
Make sure “Target Runtime” is set to “GlassFish v2 Java EE 5″
-> Finish
Right click EchoService/WebContent/index.jsp -> Run As -> Run on Server -> localhost GlassFish should be automatically selected, Finish
In the console, you’ll be prompted for the admin username and password – enter user: admin, pass:adminadmin
If all goes well you should see an emphatic Hello World!
Write, deploy, and test an “Echo” Web Service
In the EchoService project -> New -> Class -> Name:Echo, Package:echo -> Finish
Paste the following:
package echo;import javax.jws.WebService;
@WebServicepublic class Echo {public String echo(String input) { return input;}}
The only thing you need to do to write a web service is to add the @WebService annotation.
Right click Echo.java -> Run As -> Run on Server -> Finish
Eclipse will display an error page at “http://localhost:8080/EchoService/WEB-INF/classes/echo/Echo.java”, but thats fine, because that’s not what we’re trying to accomplish.
To see the service, use the GlassFish admin GUI
Go to http://localhost:4848/ user: admin pass: adminadmin
On the left panel, click “Web Services” -> Echo -> Test ->
follow the http link (http://localhost:8080//EchoService/EchoService?Tester)
Enter “Hello World”, then you should see the SOAP messages:
SOAP Request:
<?xml version="1.0" encoding="UTF-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header/><S:Body><ns2:echo xmlns:ns2="http://echo/"><arg0>Hello World!</arg0></ns2:echo></S:Body></S:Envelope>
SOAP Response:
<?xml version="1.0" encoding="UTF-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:echoResponse xmlns:ns2="http://echo/"><return>Hello World!</return></ns2:echoResponse></S:Body></S:Envelope>
Install Flex Builder
Write the “Echo” client
Create an EchoService Flex Client (sources: here and here and here (source code), Flex docs were also useful)
The URL of your WSDL file is at http://localhost:8080//EchoService/EchoService?WSDL
The following MXML code defines a simple GUI which calls the EchoService
<?xml version="1.0" encoding="utf-8"?><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"><mx:Script><![CDATA[ import mx.controls.Alert; import mx.rpc.events.ResultEvent; import mx.rpc.events.FaultEvent;
private var startTime:int; private var endTime:int;
private function button_click():void { webService.echo.send(textInput.text); startTime = getTimer(); timeLabel.text = ""; }
private function echo_result(evt:ResultEvent):void { resultLabel.text = "Result: "+evt.result.toString() calcTime(); }
private function echo_fault(evt:FaultEvent):void { Alert.show(evt.type); calcTime(); }
private function calcTime():void { endTime = getTimer(); timeLabel.text = "Time: " + (endTime - startTime) + "ms"; }]]></mx:Script>
<mx:WebService id="webService"<!-- replace this ip address with your own --> wsdl="http://129.63.16.175:8080//EchoService//EchoService?WSDL"><mx:operation name="echo" resultFormat="object" result="echo_result(event);" fault="echo_fault(event);"></mx:operation></mx:WebService>
<mx:Button id="button" label="Call service" click="button_click();" /><mx:Label text="input:" /><mx:TextInput id="textInput" text="Hello Flex!"/><mx:Label id="timeLabel" /><mx:Label id="resultLabel" /></mx:Application>
Replace the ip of the web service with “localhost” or your server ip, which you can find by executing
ifconfig | grep ‘inet addr:’| grep -v ’127.0.0.1′ |cut -d: -f2 | awk ‘{ print $1}’
Alternatively, you could set up the web service in ActionScript as opposed to MXML:
<?xml version="1.0" encoding="utf-8"?><mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()"><mx:Script><![CDATA[ import mx.rpc.soap.WebService; import mx.controls.Alert; import mx.rpc.events.ResultEvent; import mx.rpc.events.FaultEvent;
private var startTime:int; private var endTime:int; private var webService:WebService;
private function init():void{ webService = new WebService(); //replace this ip address with your own webService.wsdl = "http://129.63.16.175:8080//EchoService//EchoService?WSDL" webService.echo.resultFormat = "object" webService.echo.addEventListener("result", echo_result); webService.echo.addEventListener("fault", echo_fault); webService.loadWSDL(); }
private function button_click():void { webService.echo.send(textInput.text); startTime = getTimer(); timeLabel.text = ""; }
private function echo_result(evt:ResultEvent):void { resultLabel.text = "Result: "+evt.result.toString() calcTime(); }
private function echo_fault(evt:FaultEvent):void { Alert.show(evt.type); calcTime(); }
private function calcTime():void { endTime = getTimer(); timeLabel.text = "Time: " + (endTime - startTime) + "ms"; }]]></mx:Script>
<mx:Button id="button" label="Call service" click="button_click();" /><mx:Label text="input:" /><mx:TextInput id="textInput" text="Hello Flex!"/><mx:Label id="timeLabel" /><mx:Label id="resultLabel" /></mx:Application>
Notes:
Build Failing due to Constructor issue
I was confused for a while about this error:
CLI171 Command deploydir failed : Deploying application in domain failed; Deployment Error — Exception occured in the wsgen process javax.xml.ws.WebServiceException: Unable to create JAXBContext
BUILD FAILED
/home/curran/workspace/.metadata/.plugins/org.eclipse.jst.server.generic.core/serverdef/sunappsrv-ant.xml:203: The following error occurred while executing this line:
/home/curran/workspace/.metadata/.plugins/org.eclipse.jst.server.generic.core/serverdef/sunappsrv-ant.xml:119: exec returned: 1
I realized by reading the log file and reading this that the reason is because the exception type my service threw didn’t have a no-argument constructor, which is apparently a requisite property of objects you send over the wire FROM a seb service.
Tracing Server-side Exceptions
they are appended to the log file at ~/opt/glassfish/domains/domain1/logs/server.log
To see the latest exceptions:
cat ~/opt/glassfish/domains/domain1/logs/server.log
Adding JARS to the server code dependency
put the jars you need into WebContent/WEB_INF/lib of your project
Enjoy!