Thursday, February 15, 2007

Handling Web Service exception in Flex code

In this post I'll explain how to propogate exception details from Web Services into Flex. I am using java XFire web service implementation but similar steps can be applied to different ws implementations.

Let assume you defined a web servie method:

public String getSomething() throws ClientException

where ClientException would contain information like exception id and message.

If the method throw an exception, on Flex side you want to extract id and message to present it to user.To do this in Flex we can use standard "fault" handler (I assume you know how to call web service from Flex so I would go into much details there)



service.doSomething.addEventListener("result", responder.result);
service.doSomething.addEventListener("fault", responder.fault);
service.doSomething();


Here we use already defined web service (service) and assign "result" handler to handle normal flow and "fault" handler to handler any exception, including our own ClientException.

responder.fault may look like:



public function fault(info:Object):void {

var ns:Namespace = new Namespace("http://www.acme.com");
default xml namespace = ns;

var xml:XML = new XML(info.fault.faultDetail);

if (xml.id[0] == "123") {
show(xml.message[0]);
}
}



Here we acccess Flex provided info object that includes fault member variable. Using fault var we can access exception details (in this case id and message) and process this data.

So far nothing really special done on Flex side.

Now let's look how to implement server side. I would not go into details how expose web service in XFire (you can find this info in XFire docs). Instead let's focus on Flex specific moments. The most important one is that Flex would not process SOAP fault message if HTTP status code other then 200. Here is excerpt from Flex manual:

> "On web browsers, when a service returns any status code other than 200,
> Adobe Flash Player
> cannot read the body of the response. If the status code is 500 and the
> body contains a
> fault, there is no way to get to the fault. The proxy works around this
> issue by forcing the
> status code for faults to 200; the player passes the body of the
> response along with the
> fault intact. "

It means that we need to add a code on server side to ensure that response code is equal to 200 when we throw an exception. When exception thrown from XFire HTTP status code would be 500 (web services standard implies it), so we need to create a servlet filter that would set HTTP status code to 200 to allow Flex web service engine access SOAP body.

This is also pretty standard stuff, you would need to define filter and associate it with XFire servlet in web.xml (you can find more info on filter here):



Exception filter would like:



import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

public class ExceptionFilter implements Filter {

public void destroy() {
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {

HttpServletResponse httpResponse = (HttpServletResponse) response;
ExceptionHttpServletResponseWrapper wrapper = new ExceptionHttpServletResponseWrapper(httpResponse);

chain.doFilter(request, wrapper);
}

public void init(FilterConfig arg0) throws ServletException {
}

}



And you to define HttpServletResponsWrapper that would control setStatus() method to ensure that status code is 200.



import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class ExceptionHttpServletResponseWrapper extends
HttpServletResponseWrapper {

public ExceptionHttpServletResponseWrapper(HttpServletResponse response) {
super(response);
}

@Override
public void setStatus(int statusCode) {
if (statusCode == 500) {
super.setStatus(200);
}
}
}



The above code can be used for any web service implementation.

We still need to add some specific way XFire handles user's exception. One way to it is to create a custom ClientExceptionDetails that contain id and message.



public class ClientExceptionDetails {

private int id;
private String message;

public ClientExceptionDetails(int id, String message) {
super();
this.id = id;
this.message = message;
}

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}



And make sure that ClientException uses this info:



import javax.xml.namespace.QName;

import org.codehaus.xfire.fault.FaultInfoException;
import org.codehaus.xfire.fault.XFireFault;

public class ClientException extends FaultInfoException {

private ClientExceptionDetails faultDetail;

public ClientException(String message, ClientExceptionDetails detail) {
super(message);

this.faultDetail = detail;
}

public ClientExceptionDetails getFaultInfo() {
return faultDetail;
}

public static QName getFaultName() {
return new QName("http://www.acme.com", "ClientException");
}
}



(Check XFire doc for more info about FaultInfoException)

That's all, now when you throw ClientException, XFire would use ClientExceptionDetails to populat SOAP body with id and message that you can extract later on Flex side from fault.faultDetail.

12 comments:

Chua Chee Seng said...

Hi,

I cannot get it working with Axis, I am using Axis 1.4. I have set the HTTP status code from 500 to 200 using HttpServletResponseWrapper. However, instead of calling on the callback function for fault, Flex calls the success callback function. The soap response is a soap fault. Is it because status code 200 indicate that the invocation succeed without fault?

Thanks for any help in advance.

Best Regards,
Chee Seng

Chua Chee Seng said...

Hi,

It does not work in XFire too, the succeed callback is called instead of the fault callback. Although the soap message is populated with the correct exception details, but calling succeed callback leaves me no idea to handle the exception details. Any idea?

Thanks.

Best Regards,
Chee Seng

RD said...

It's difficult to say without looking into the code - it works for me. I guess you already checked that: service.doSomething.addEventListener("fault", responder.fault); is assigned to "fault"?

Optimus Paul said...

I have yet to try this, but I will soon. Why can't Adobe just fix Flex? It is very bothersome to have to change my SOAP services for one client.

Martin Fox said...

Hi, i want to do this whit axis, do u know how?

Abhishek said...

hi
i wanted to use a flex client with a web service. when my web service send any notification to flex it should able to process that notification and display result.

SG said...

this is working fine. but if i have to use the same exception in another service in the same project I have to define it again. Is there another way to call this exception from a separate package to all the services in our project

narahari said...

this fine...

but i am using .swf in jsp working fine. when it is comes to debug i am unable to debug my flex files which are part of jsp.

i am using eclipse it contains 2 different project 1) java 2) flex

flex out put directory is pointing to one of the folder in in my java projects. then each of the jsp using this .swf file.

for this how can i debug my flex code.

Unknown said...

Hi,

After testing this method with Axis 1 v1.4, i found that it works in Flex if you don't use the Data>Import Web services to create the AS3 stub class . You have to use the Webservice tag to declare your WS and make the mapping manually if you want results on particular objects.

Bye.
P.S : Sorry for my poor english, i'm french.

Unknown said...

It worked for me perfectly with axis2. Thanx a lot.

Kitty said...

楽々稼げる高額携帯メールレディ募集
稼げるチャットレディー求人情報
素人OK!すぐに稼げるアルバイト情報
夜間だけでも稼げる高収入在宅バイト
簡単に稼げる高額携帯メールレディ募集
稼げるアダルト無し高収入チャトレ募集
高時給♪未経験者でも稼げる在宅ワーク情報
昼間だけOK!簡単に稼げるアルバイト情報
稼げる高単価携帯メールレディ求人情報
初心者OK!手軽に稼げるバイト情報
稼げる安全高額メールレディ募集
彼に内緒で稼げる高時給携帯チャトレ募集
主婦でもお家で稼げる仕事
高収入!素人でも稼げる在宅バイト情報
初めてでも安心♪携帯メールレディ求人ガイド
主婦でも稼げる携帯チャトレ
セキュリティ万全♪安全に稼げるバイト情報
短時間で稼げる携帯チャットレディー
人妻OK!自宅で稼げる副業情報
人妻OK!手軽に稼げる在宅ワーク情報
昼間だけOK!楽に稼げる小遣い稼ぎ情報
夜間だけOK!すぐに稼げる副業情報
手軽に出来る副収入
稼げる大手高額メールレディー募集
初めてでもOK!楽々稼げるバイト情報
お家で稼げるチャトレ
子持ち歓迎♪稼げる高収入アルバイト
夜だけOK!手軽に稼げる仕事情報
高収入!未経験者でも稼げる家仕事情報
未経験者OK!家で稼げる在宅ワーク情報
簡単に稼げる高額バイト
気軽に稼げる高額バイト
素人でも稼げる高額携帯チャトレ募集
高時給チャットレディー求人サイト
楽に稼げる高収入在宅ワーク

Kitty said...

優良モバイルサイト30代女性に人気の携帯自宅バイトが良いみたいです。優良情報満載1日1万以上のチャットレディに今すぐGO~マル秘情報満載育児中の主婦でも月50万以上稼げるはとてもよろしいと思いました。人気モバイルサイトこれなら子持ち主婦でも働けるはとてもよろしいと思いました。人気サイト顔出し無しでも安全 チャットレディーは楽しいね。人気サイト学生・フリーター 稼ぎやすいチャトレ がいい感じ、お勧め育児中の主婦でも時給3000円以上稼げるが参考になりました♪役立つ彼氏に内緒で稼げる チャットレディーを参考にしてみてね★稼ぐための参考サイト通勤不要 携帯メールレディだね^^優良情報が見放題専業主婦でも月20万以上稼げるですよ!見ないと損する学生・フリーターに人気の高収入チャットレディーですよ!本物の安心サポート♪稼げる携帯メールレディーは楽しいね。役立つ子育て中の主婦でも1日5000円以上稼げるはとてもよろしいと思いました。おすすめ優良夜間だけで稼げる携帯メールレディーにいこう。オススメの大学生 高収入仕事に今すぐGO~イイ情報がたくさんの専業主婦 高収入チャットレディー求人だね^^見ないと損する主婦・人妻が稼ぎやすい仕事に今すぐGO~素敵なサイト旦那に内緒で稼げる メールレディーがイイよ、優良情報満載メールだけ 稼ぎやすいチャトレ は見ました?某掲示板でも評判のアダルト無し 稼ぎやすい内職 を参考に