开发者

Transaction management in a SOAP server implementation

I have a standard jax-ws webservice set up that uses Spring for DI and Hibernate for persistence. Now in Spring you'd normally wrap your request in a custom filter and execute beginTransaction() and commit() / rollback() on the Hibernate session depending whether the execution went through without errors or not.

For the soap web client开发者_JAVA技巧 however, this execution chain is not used and therefor no transaction management can easily be set up like this. Of course I also want to avoid wrapping each of my @WebMethod implementations in

session.beginTransaction();
try {
   ... 
   session.commit();
}
catch (RuntimeException e) {
   session.rollback();
   throw e;
}

so I looked into other possibilities. Apparently the JSR allows to configure SOAPHandler's (via @HandlerChain) that intercept SOAP traffic after incoming and before outgoing soap messages are sent, but I wonder if I am on the right track with that or doing it wrong...

Do you guys know of other alternatives?


I went down the SOAPHandler route and it seems to work nicely:

public class SOAPServiceHandler implements SOAPHandler<SOAPMessageContext>
{
    @Override
    public void close(MessageContext mc)
    {
    }

    @Override
    public boolean handleFault(SOAPMessageContext smc)
    {
        MyHibernateUtil.rollbackTransaction();
        return true;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext smc)
    {
        Session session = MyHibernateUtil.getCurrentSession();
        Boolean outbound = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!outbound)
        {
            session.beginTransaction();
            session.setFlushMode(FlushMode.COMMIT);
            return true;
        }

        SOAPBody body = null;
        try
        {
            body = smc.getMessage().getSOAPBody();
        }
        catch (SOAPException e)
        {
        }

        session.flush();
        session.setFlushMode(FlushMode.AUTO);

        if (body == null || body.hasFault())
        {
            session.getTransaction().rollback();
        }
        else
        {
            session.getTransaction().commit();
        }

        return true;
    }

    @Override
    public Set<QName> getHeaders()
    {
        return null;
    }
}

This is my applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:ws="http://jax-ws.dev.java.net/spring/core"
    xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
            http://jax-ws.dev.java.net/spring/core
            http://jax-ws.dev.java.net/spring/core.xsd
            http://jax-ws.dev.java.net/spring/servlet
            http://jax-ws.dev.java.net/spring/servlet.xsd"> 

    <bean id="SoapServiceImpl" class="path.to.SOAPServiceImpl" />       
    <bean id="SoapServiceHandler" class="path.to.SOAPServiceHandler" /> 

    <wss:binding url="/soap">
        <wss:service>
            <ws:service bean="#SoapServiceImpl">
                <ws:handlers>
                    <ref bean="SoapServiceHandler" />
                </ws:handlers>
            </ws:service>
        </wss:service>
    </wss:binding>
</beans>

Feedback welcome!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜