分享

XFire as a webservice provider in Spring

 liwp_Stephen 2008-09-19

I decided to go with xfire for exposing business objects as web services. This is a pretty lightweight toolkit..the best thing is that i can expose any regular interface as a webservice, without changing any code.

Here‘s a bit of sample code

public interface ProgramInfoService {
	public void refreshProgramData(ProgramInfoCollection coll);
	public Program[] getAllProgramInfo();
}

-- from spring config --

<bean id="programInfoServiceBean" class="org.caisi.integrator.program.ws.ProgramInfoServiceImpl">
 <property name="programInfoDAO">
  <ref local="ProgramInfoDAO"/>
 </property>
</bean>

    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="urlMap">
            <map>
                <entry key="/ProgramInfoService">
                    <ref bean="programInfoService"/>
                </entry>
            </map>
        </property>
    </bean>
   
    <bean id="programInfoService" class="org.codehaus.xfire.spring.remoting.XFireExporter">
        <property name="serviceFactory">
            <<ref bean="xfire.serviceFactory"/>
        </property>
        <property name="xfire">
            <ref bean="xfire"/>
        </property>
        <property name="serviceBean">
            <ref bean="programInfoServiceBean"/>
        </property>
        <property name="serviceInterface">
            <value>org.caisi.integrator.program.ws.ProgramInfoService</value>
        </property>
        <property name="inHandlers">
        	<ref bean="authenticationHandler"/>
        	
        </property>
    </bean>

That‘s pretty much all there is to it. You can create handlers to provide any kind of service specific functionality. I created one to handle authentication.. the example was borrowed pretty much from the xfire site, but upgraded to use the latest cvs code.

public class AuthenticationHandler extends AbstractHandler {

	private static Log log = LogFactory.getLog(AuthenticationHandler.class);
	private final String TOKEN_NS="http://ws.program.integrator.";
	private AuthenticationManager authenticationManager;
	
	public void setAuthenticationManager(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}
	
	public void invoke(MessageContext context) throws Exception {

		if (context.getInMessage().getHeader() == null)
        {
            throw new XFireFault("Request must include company authentication token.", 
                                 XFireFault.SENDER);
        }
		Namespace ns = Namespace.getNamespace(TOKEN_NS);
		
		Element header = context.getInMessage().getHeader();
		Element token = header.getChild("AuthenticationToken",ns);
		
		if (token == null)
        {
            throw new XFireFault("Request must include authentication token.", 
                                 XFireFault.SENDER);
        }

		String username = token.getChild("Username",ns).getText();
		String password = token.getChild("Password",ns).getText();

        try {
        	UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username,password);
        	authenticationManager.authenticate(auth);  	
        }catch(Exception e) {
        	log.warn(e);
        	throw new XFireFault("Authentication Failed.", 
                    XFireFault.SENDER);
        }

	}

}

I‘m using Acegi for doing the actual authentication.

Client code was kind of a pain to write. But managed to get something together.

		public static void main(String[] args) throws Exception{
			XFire xfire = XFireFactory.newInstance().getXFire();
			XFireProxyFactory factory = new XFireProxyFactory(xfire);
			
			Service serviceModel = new ObjectServiceFactory().create(ProgramInfoService.class);
			ProgramInfoService service = (ProgramInfoService) factory.create(serviceModel, "http://localhost:8080/program-integrator/ProgramInfoService");
			XFireProxy proxy =  (XFireProxy)Proxy.getInvocationHandler(service);
			proxy.getClient().addOutHandler(new ClientAuthHandler(args[0],args[1]));
			proxy.getClient().setTransport(new SoapHttpTransport());

....
}

from this code, you can basically invoke any method on the interface. here‘s the outgoing authentication handler.

public class ClientAuthHandler extends AbstractHandler {

	private String username = null;
	private String password = null;
	
	public ClientAuthHandler() {
	}
	
	public ClientAuthHandler(String username,String password) {
		this.username = username;
		this.password = password;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}
	
	public void invoke(MessageContext context) throws Exception {
		Element el = context.getOutMessage().getHeader();
		final Namespace ns = Namespace.getNamespace("caisi","http://ws.program.integrator.");  
        el.addNamespaceDeclaration(ns);
        
        Element auth = new Element("AuthenticationToken", ns);
        Element username_el = new Element("Username",ns);
        username_el.addContent(username);
        Element password_el = new Element("Password",ns);
        password_el.addContent(password);
        auth.addContent(username_el);
        auth.addContent(password_el);
        el.addContent(auth);
	}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约