Codehaus XFire
DocumentationQuicklinksDevelopers
Sponsors |
What is the use case for not using web services?One example of needing to parse a SOAP message is if you are using a message driven bean to listen to a JMS queue. The text received from the queue is a String with a SOAP message. How do you go about parsing the SOAP to get at the body? Also, how do you leverage XFire's flexible binding mechanism to marshall the SOAP Body for you? Example 1: Incoming SOAP message retrieved from a JMS queueHere is a typical message driven bean receiving a text message: MyMDB.java public void onMessage(Message message) { TextMessage textMessage = (TextMessage) message; String responseString = invoker.invokeService("TicketReceiptMessageService", textMessage.getText()); System.out.println("Response is:" + responseString); } In this example XFire is used to call a service named 'TicketReceiptMessageService' passing it the marshalled SOAP body. The 'TicketReceiptMessageService' needs to have an operation similiar to the SOAP body element so that XFire can determine which method to call on the service. Here is our incoming SOAP message: <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <orchLayerProcessTicket xmlns="http://com/ticketingServices/ticket/"> <internalTrackingID xmlns="">0</internalTrackingID> <busOrgID xmlns="">jms_test</busOrgID> <ticketRequest xmlns=""/> </orchLayerProcessTicket> </SOAP-ENV:Body> </SOAP-ENV:Envelope> Here is the operation on the service which handles the incoming SOAP request: TicketReceiptMessageService.java public OrchLayerProcessTicketResponseDocument OrchLayerProcessTicket(OrchLayerProcessTicketDocument document) { OrchLayerProcessTicketResponseDocument returnValue = OrchLayerProcessTicketResponseDocument.Factory.newInstance(); OrchLayerProcessTicketResponseType res = returnValue.addNewOrchLayerProcessTicketResponse(); ResultCode code = res.addNewResultCode(); code.setMessage(document.getOrchLayerProcessTicket().getBusOrgID()); return returnValue; } XMLBeans was used as the binding mechanism to marshall the SOAP Body. Before using XMLBeans as the binding tool you need to use the xmlbean Ant task to generate binding classes from your XSD schema. Configuring XFire in the xfire.xml file using Spring to handle this use case: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="xfire.serviceRegistry" class="org.codehaus.xfire.service.DefaultServiceRegistry"/> <bean id="xfire.transportManager" class="org.codehaus.xfire.transport.DefaultTransportManager" init-method="initialize" destroy-method="dispose"/> <bean id="xfire" class="org.codehaus.xfire.DefaultXFire"> <constructor-arg index="0"> <ref bean="xfire.serviceRegistry" /> </constructor-arg> <constructor-arg index="1"> <ref bean="xfire.transportManager" /> </constructor-arg> </bean> <bean id="xfire.aegisBindingProvider" class="org.codehaus.xfire.aegis.AegisBindingProvider"> <constructor-arg index="0"> <ref bean="xfire.xmlBeansTypeRegistry"/> </constructor-arg> </bean> <bean id="xfire.inboundServiceFactory" class="org.codehaus.xfire.service.binding.ObjectServiceFactory"> <constructor-arg index="0"> <ref bean="xfire.transportManager" /> </constructor-arg> <constructor-arg index="1"> <ref bean="xfire.aegisBindingProvider" /> </constructor-arg> </bean> <bean id="xfire.xmlBeansTypeRegistry" class="org.codehaus.xfire.xmlbeans.XmlBeansTypeRegistry"/> </beans> The 'TicketReceiptMessageService' is configured in the services.xml file: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://xfire.codehaus.org/config/1.0"> <service> <name>TicketReceiptMessageService</name> <serviceFactory>#xfire.inboundServiceFactory</serviceFactory> <serviceClass>com.ticketing.TicketReceiptMessageService</serviceClass> <style>document</style> </service> </beans> The last piece of the puzzle is the invocation code to handle a SOAP request and pass it to an XFire Channel to do the rest: ServiceInvokerImpl.java public String invokeService(String serviceName, String request) throws ServiceInvokerException { return invokeService(serviceName, new ByteArrayInputStream(request.getBytes())); } public String invokeService(String serviceName, InputStream stream) throws ServiceInvokerException { ByteArrayOutputStream out = null; XMLStreamReader reader = null; try { out = new ByteArrayOutputStream(); MessageContext context = new MessageContext(); context.setXFire(getXFire()); context.setProperty(Channel.BACKCHANNEL_URI, out); context.setService(getXFire().getServiceRegistry().getService(serviceName)); reader = STAXUtils.createXMLStreamReader(stream, "UTF-8", null); InMessage msg = new InMessage(reader); Transport t = getXFire().getTransportManager().getTransport(LocalTransport.BINDING_ID); Channel c = t.createChannel(); c.receive(context, msg); // Validate that we don't have a SOAP Fault if (StringUtils.contains(out.toString(), "soap:Fault")) { throw new ServiceInvokerException("SOAP Fault thrown:" + out.toString()); } } catch (Exception e) { throw new ServiceInvokerException(e.getMessage(), e); } finally { try { reader.close(); out.close(); } catch (Throwable e) { throw new ServiceInvokerException(e.getMessage(), e); } } return out.toString(); } |