Announcement Announcement Module
Collapse
No announcement yet.
Poor Response performance with Axiom Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Poor Response performance with Axiom

    (Let me apologize in advance for my poor English)

    Hello,

    First, i come from Axis2, and i'm trying to use Jibx with Spring-WS.
    I have configured spring to use the StAX "optimised" factory :

    Code:
    <bean id="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
    	<property name="payloadCaching" value="false" />
    </bean>
    But this is the point : i've compared performance between Axis2 and Spring-Ws with the same JibX beans implementation.
    I've figure out that the unmarshalling (request) is fine, but the response is far slower than Axis2. Especially with large SOAP response (>50k)

    For the tests, i've used an Axis2 client, with the same jibx beans too. I've put a System.nanoTime() before each send in client side, and in the process Layer in server side. Both client and server (Tomcat 6) are on the same computer.
    Axis2 : Request time 50ms, Response time 60ms
    Spring-Ws : Request time 50ms, Response time 200ms


    So i've taken a look at the code and found some misconception with Jibx marshalling...

    Code:
    protected void marshalSaxHandlers(Object graph, ContentHandler contentHandler, LexicalHandler lexicalHandler)
    		throws XmlMappingException {
    try {
    	// JiBX does not support SAX natively, so we write to a buffer first, and transform that to the handlers
    	ByteArrayOutputStream os = new ByteArrayOutputStream();
    	marshalOutputStream(graph, os);
    	ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
    	Transformer transformer = transformerFactory.newTransformer();
    	SAXResult saxResult = new SAXResult(contentHandler);
    	saxResult.setLexicalHandler(lexicalHandler);
    	transformer.transform(new StreamSource(is), saxResult);
    }
    As you can see, it appears to be time consuming...

    This is how JibxMarshaller marshalls the response :
    - AxiomResult extends a SaxResult, this is why JibxMarshaller.marshalSaxHandlers() is called
    - Jibx beans are marshalled in a ByteArrayOutputStream => OK
    - Then this ByteArray goes through a SAXParser, which builds the axiom SOAP Body, using a SoapFactory...
    - And then the SOAP envelope is serialized in the TransportOutputStream... (not shown here)

    Beans =>(XmlPull)=> ByteArray => SAX => Axiom(StAX) => Result => Stream


    Knowing that Jibx does a good job, could we marshall the beans directly inside the SOAP Body ?

    This is how Axis2 proceed :

    Code:
    private org.apache.axiom.om.OMElement mappedChild(Object value, org.apache.axiom.om.OMFactory factory) {
    	org.jibx.runtime.IMarshallable mrshable = (org.jibx.runtime.IMarshallable) value;
    	org.apache.axiom.om.OMDataSource src = new org.apache.axis2.jibx.JiBXDataSource(mrshable, bindingFactory);
    	int index = mrshable.JiBX_getIndex();
    	org.apache.axiom.om.OMNamespace appns = factory.createOMNamespace(bindingFactory.getElementNamespaces()[index], "");
    	return factory.createOMElement(src, bindingFactory.getElementNames()[index], appns);
    }
    Last edited by bugsan; Mar 10th, 2008, 04:13 PM.

  • #2
    Done.

    I've written a new MessageEndPoint for Jibx, it's 3 time faster with large SOAPEnvelope (>50k), and now exactly as fast as Axis2/Jibx.

    The root problem was AxiomResult. Just for proof of concept, i've modified it to have acces to OMFactory and OMContainer.

    JiBXDataSource is part of axis2-jibx-1.3.jar (the class has no dependancies with axis2).

    Code:
    import javax.xml.stream.XMLStreamReader;
    import javax.xml.transform.Result;
    import javax.xml.transform.Source;
    
    import org.apache.axiom.om.OMContainer;
    import org.apache.axiom.om.OMDataSource;
    import org.apache.axiom.om.OMElement;
    import org.apache.axiom.om.OMFactory;
    import org.apache.axis2.jibx.JiBXDataSource;
    import org.jibx.runtime.BindingDirectory;
    import org.jibx.runtime.IBindingFactory;
    import org.jibx.runtime.IMarshallable;
    import org.jibx.runtime.IXMLReader;
    import org.jibx.runtime.impl.StAXReaderWrapper;
    import org.jibx.runtime.impl.UnmarshallingContext;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.util.Assert;
    import org.springframework.ws.context.MessageContext;
    import org.springframework.ws.soap.axiom.AxiomResult;
    import org.springframework.xml.transform.StaxSource;
    
    public abstract class AbstractJibxMessageEndPoint implements MessageEndpoint, InitializingBean {
    	private Class bindingFactoryClass;
    	private IBindingFactory bindingFactory;
    
    	public void afterPropertiesSet() throws Exception {
    		Assert.notNull(bindingFactoryClass);
    		bindingFactory = BindingDirectory.getFactory(bindingFactoryClass);
    	}
    	
    	public void setBindingFactoryClass(Class bindingFactoryClass) {
    		this.bindingFactoryClass = bindingFactoryClass;
    	}
    	
    	protected abstract Object invokeInternal(Object request) throws Exception;
    
    
    	public void invoke(MessageContext context) throws Exception {
    		Source rawSource = context.getRequest().getPayloadSource();
    		if(!(rawSource instanceof StaxSource))
    			throw new RuntimeException("JibxPayload supports only StaxSource, found "+rawSource.getClass().getName());
    		
    		Result rawResult = context.getResponse().getPayloadResult();
    		if(!(rawResult instanceof AxiomResult))
    			throw new RuntimeException("JibxPayload supports only AxiomResult, found "+rawResult.getClass().getName());
    		
    		invokeSourceResult((StaxSource)rawSource, (AxiomResult)rawResult);
    	}
    	
    	protected void invokeSourceResult(StaxSource source, AxiomResult result) throws Exception {
    		XMLStreamReader xmlReader = source.getXMLStreamReader();
    		OMFactory oMFactory = result.getFactory();
    		OMContainer oMContainer = result.getContainer();
    		
    		IXMLReader iXmlReader = new StAXReaderWrapper(xmlReader, null, true);
    		UnmarshallingContext unmarshallingContext = (UnmarshallingContext)bindingFactory.createUnmarshallingContext();
    		unmarshallingContext.setDocument(iXmlReader);
    		Object requestObject = unmarshallingContext.unmarshalElement();
    		
    		
    		Object responseObject = invokeInternal(requestObject);
    		
    		
    		if(!(responseObject instanceof IMarshallable))
    			throw new RuntimeException("JibxPayload supports only IMarshallable response object, found "+responseObject.getClass().getName());
    		
    		IMarshallable mrshable = (IMarshallable) responseObject;
    		OMDataSource dataSource = new JiBXDataSource(mrshable, bindingFactory);
    		int index = mrshable.JiBX_getIndex();
    		org.apache.axiom.om.OMNamespace appns = oMFactory.createOMNamespace(bindingFactory.getElementNamespaces()[index], "");
    		OMElement el = oMFactory.createOMElement(dataSource, bindingFactory.getElementNames()[index], appns);
    		oMContainer.addChild(el);
    	}
    }

    Comment


    • #3
      This seems similar to the approach suggested by Jim: http://jira.springframework.org/browse/SWS-302

      Comment

      Working...
      X