XML-RPC - Throwing Exceptions from Server to Client in Java
It is my first time posting here and I could not find the answer to my question during a search so lets see if I can explain myself correctly.
I am using XML-RPC as part of a large project but I will present a simplified code in which I obtain the same result.
The connection is working perfectly if I do not throw exceptions. My problem is to throw an exception from Server to Client. I get the XmlRpcException on the Client side but its cause is always null. Looks like the exception is lost on the transfer. Any idea why?
My Server:
public class JavaServer {
public Integer sum(int x, int y) throws Exception {
throw new MineException("ABABBABA");
}
public static void main (String [] args) {
try {
System.out.println("Attempting to start XML-RPC Server...");
WebServer server = new WebServer(80);
XmlRpcServer xmlRpcServer = server.getXmlRpcServer();
PropertyHandlerMapping phm = new PropertyHandlerMapping();
phm.addHandler("test", JavaServer.class);
xmlRpcServer.setHandlerMapping(phm);
XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
serverConfig.setEnabledForExceptions(true);
server.start();
System.out.println("Started successfully.");
System.out.println("Accepting requests. (Halt program to stop.)");
} catch (Exception exception) {
System.err.println("JavaServer: " + exception);
}}}
My Client:
public static void main(String[] args) {
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
try {
config开发者_如何学C.setServerURL(new URL("http://localhost:80"));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
Object[] params = new Object[] { new Integer(38), new Integer(3), };
Integer result = (Integer) client.execute("test.sum", params);
System.out.println("Results " + result);
} catch (XmlRpcException exception) {
Throwable cause = exception.getCause();
if(cause != null) {
if(cause instanceof MineException) {
System.out.println(((MineException)cause).getMessage());
}
else { System.out.println("Cause not instance of Exception"); }
}
else { System.out.println("Cause was null"); }
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I found out that by using apache xml-rpc implementation on both client and server it is possible to throw custom exceptions from the server and receive them on the client. Something just needs to be added to the server and client configuration.
Server:
WebServer server = new WebServer(80);
XmlRpcServer xmlRpcServer = server.getXmlRpcServer();
PropertyHandlerMapping phm = new PropertyHandlerMapping();
phm.addHandler("test", JavaServer.class);
xmlRpcServer.setHandlerMapping(phm);
XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
serverConfig.setEnabledForExceptions(true);
serverConfig.setEnabledForExtensions(true); //Add this line
server.start();
Client:
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
try {
config.setServerURL(new URL("http://localhost:80"));
config.setEnabledForExceptions(true);
config.setEnabledForExtensions(true); //Add this line
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
Object[] params = new Object[] { new Integer(11), new Integer(3), };
Integer result = (Integer) client.execute(config,"test.sum", params);
System.out.println("Results " + result);
} catch (XmlRpcException exception) {
System.out.println(exception.getMessage());
Throwable cause = exception.getCause();
if(cause != null) {
if(cause instanceof MyException) {
System.out.println(((MyException)cause).getMessage());
}
else { System.out.println("Cause not instance of Exception."); }
}
else { System.out.println("Cause was null."); }
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Then everything works as expected.
Some other piece of (hopefully helpful) advice.
So, you want to enable the extensions for exceptions, but you are running the service within a Servlet inside (a full-fledged) web server like say, Apache Tomcat. Then you need to enable the extensions and exceptions by configuring them in the web.xml file (WEB-INF\web.xml):
<servlet>
<servlet-name>My_XMLRPC_Servlet</servlet-name>
<servlet-class>com.stackoverflow.server.MyXmlRpcServlet</servlet-class>
<init-param>
<param-name>enabledForExtensions</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>enabledForExceptions</param-name>
<param-value>true</param-value>
</init-param>
...
</servlet>
After a bit of investigation I found the answer... the short answer is that it is not possible to send custom exceptions through the XMLRPC channel according to the XMLRPC spec:
Can the struct contain other members than faultCode and faultString?
A fault struct may not contain members other than those specified. This is true for all other structures. We believe the specification is flexible enough so that all reasonable data-transfer needs can be accomodated within the specified structures. If you believe strongly that this is not true, please post a message on the discussion group.
The not so short answer is that it is possible to do it in another way if the server throw instead a XmlRpcException.
public Integer sum(int x, int y) throws XmlRpcException {
// XmlRpcException(exceptionCode,exceptionMessage)
throw new XmlRpcException(1,"Message");
}
And on the client side:
catch (XmlRpcException exception) {
System.out.println("Exception code: " + exception.code);
System.out.println("Exception message: " + exception.getMessage());
}
If the client and server agree to use defined codes, the exception can be identified through the code and message. It is not really custom exceptions but it is the most near we can get to it.
精彩评论