JAX-WS:异步与Handler机制

前面介绍了如何创建基于JAX-WS的webservice以及传递对象的一些相关内容,下面介绍下异步和Handler机制

1、异步

JAX-WS支持客户端的异步调用。在Server与普通的没多大区别,这里声明一个server服务:

@WebService(serviceName = "asynJaxWsService", endpointInterface = "org.ws.server.ws.chap3.AsynJaxWsService")
public class AsynJaxWsServiceImpl implements AsynJaxWsService {

    @WebMethod
    public @WebResult
    Address asynAddress(String id) {
        Address address = new Address();
        address.setCity("chengdu");
        address.setStreet("xxxx");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return address;
    }

}

 在发布服务后,生产客户端代码需要指定jaxws/bind文件,对于异步的bing.xml如下:

<bindings   
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
	xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
	wsdlLocation="http://localhost:8080/service/asynJaxWsService?wsdl"
	xmlns="http://java.sun.com/xml/ns/jaxws">
	<bindings node="wsdl:definitions">
		<enableAsyncMapping>true</enableAsyncMapping>
	</bindings>
</bindings>

然后生产客户端代码命令:

wsimport -p org.sample.ws.client.ws.chap3 -keep http://localhost:8080/service/asynJaxWsService?wsdl -b ./binding.xml

 在生产的客户端代码中提供了两种方式来异步调用:

public Response<AsynAddressResponse> asynAddressAsync(
        @WebParam(name = "arg0", targetNamespace = "")
        String arg0);

public Future<?> asynAddressAsync(
        @WebParam(name = "arg0", targetNamespace = "")
        String arg0,
        @WebParam(name = "asyncHandler", targetNamespace = "")
        AsyncHandler<AsynAddressResponse> asyncHandler);

可通过如下方式调用:

AsynJaxWsService jaxWs = new AsynJaxWsService_Service().getAsynJaxWsServiceImplPort();

jaxWs.asynAddressAsync("123", new AsyncHandler<AsynAddressResponse>() {

    public void handleResponse(Response<AsynAddressResponse> res) {
        try {
            AsynAddressResponse response = res.get();
            Address address = response.getReturn();
            System.out.println(ToStringBuilder.reflectionToString(address, ToStringStyle.SHORT_PREFIX_STYLE));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
});

Response<AsynAddressResponse> response = jaxWs.asynAddressAsync("123");
while (!response.isDone()) {
    System.out.println("not ending....");
}
AsynAddressResponse addressResponse = response.get();
Address address = addressResponse.getReturn();
System.out.println(ToStringBuilder.reflectionToString(address, ToStringStyle.SHORT_PREFIX_STYLE));

 

2、Handler机制

Handler机制(Filter、Interceptor)是很多框架必不可少的东西,甚至是构建在这个概念之上。在JAX-WS中提供了两种Handler机制:Logical Handlers and Protocol Handlers,简单地说前者处理业务上的后者处理访问等header层,更多信息见这里。我们这里要实现的一个简单授权访问的例子,就是基于ProtocolHandler(SOAPHandler),通过header中创建相应的节点来判断用户名或密码达到校验的目录。

首先来看看server端代码,自定义AuthHandler需要实现SOAPHandler:

public class AuthHandler implements SOAPHandler<SOAPMessageContext> {

    public boolean handleMessage(SOAPMessageContext context) {
        boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        if (!isRequest) {

            try {
                SOAPMessage soapMsg = context.getMessage();
                SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
                SOAPHeader soapHeader = soapEnv.getHeader();

                if (soapHeader == null) {
                    soapHeader = soapEnv.addHeader();
                    generateSOAPErrMessage(soapMsg, "No SOAP header.");
                }

                Iterator<?> it = soapHeader.extractHeaderElements(SOAPConstants.URI_SOAP_ACTOR_NEXT);

                if (it == null || !it.hasNext()) {
                    generateSOAPErrMessage(soapMsg, "No header block for next actor.");
                }

                //a simple way to handle authorize:通过nodeName和value来判断
                while (it.hasNext()) {
                    Node node = (Node) it.next();
                    if ("auth".equals(node.getNodeName()) && "aaaaaaaaaaaa".equals(node.getValue()))
                        return true;
                }

                generateSOAPErrMessage(soapMsg, "invalid user");
                //tracking
                soapMsg.writeTo(System.out);

            } catch (SOAPException e) {
                System.err.println(e);
            } catch (IOException e) {
                System.err.println(e);
            }

        }
        return true;//返回true是指向责任链中的下一个事物

    }

    public boolean handleFault(SOAPMessageContext context) {
        return true;
    }

    public void close(MessageContext context) {

    }

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

    private void generateSOAPErrMessage(SOAPMessage msg, String reason) {
        try {
            SOAPBody soapBody = msg.getSOAPPart().getEnvelope().getBody();
            SOAPFault soapFault = soapBody.addFault();
            soapFault.setFaultString(reason);
            throw new SOAPFaultException(soapFault);
        } catch (SOAPException e) {
        }
    }

}

 在handler-chain.xml中声明

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains 
	xmlns:javaee="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	<javaee:handler-chain>
		<javaee:handler>
			<javaee:handler-class>org.ws.server.ws.chap7.AuthHandler</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
</javaee:handler-chains>

server接口没多大变化,只需要添加@HandlerChain(file = "handler-chain.xml")指定配置文件

@WebService
@HandlerChain(file = "handler-chain.xml")
public class JaxWsHandlerServiceImpl implements JaxWsHandlerService {

    @WebMethod
    public String sayHello() {
        return "Hello, Service";
    }

}

 发布即可完成server端的配置。

接下来看看客户端,通过命令生成客户端代码后,同样需要编写handler,需要处理就是在SOAP消息的Header中添加Node,起name和value分别对应server端的配置:

public class JaxWsClientHandler implements SOAPHandler<SOAPMessageContext> {

    public boolean handleMessage(SOAPMessageContext context) {
        System.out.println("Client : handleMessage()......");

        Boolean isRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        //if this is a request, true for outbound messages, false for inbound
        if (isRequest) {

            try {
                SOAPMessage soapMsg = context.getMessage();
                SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
                SOAPHeader soapHeader = soapEnv.getHeader();

                //if no header, add one
                if (soapHeader == null) {
                    soapHeader = soapEnv.addHeader();
                }

                //add an node named "auth"
                QName qname = new QName("http://handler.sws.com/", "auth");
                SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(qname);
                
                //set attribute value
                soapHeaderElement.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT);
                soapHeaderElement.addTextNode("aaaaaaaaaaaa");
                soapMsg.saveChanges();

                //tracking
                soapMsg.writeTo(System.out);

            } catch (SOAPException e) {
                System.err.println(e);
            } catch (IOException e) {
                System.err.println(e);
            }

        }
        return true;
    }

    public boolean handleFault(SOAPMessageContext context) {
        return true;
    }

    public void close(MessageContext context) {

    }

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

}

其他工作与服务端一样,编写handler-chain.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains 
	xmlns:javaee="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	<javaee:handler-chain>
		<javaee:handler>
			<javaee:handler-class>org.sample.ws.client.ws.chap7.main.JaxWsClientHandler</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
</javaee:handler-chains>

同时在生成的客户端代理类中需要加入该hander-chain,看起来是这样的:

@WebServiceClient(name = "JaxWsHandlerServiceImplService", targetNamespace = "http://impl.chap7.ws.server.ws.org/", wsdlLocation = "http://localhost:8080/service/jaxWsAuthSrevice?wsdl")
@HandlerChain(file = "handler-chain.xml")
public class JaxWsHandlerServiceImplService
    extends Service

这样就完成了一个简单的实例,按照普通的调用即可:

        JaxWsHandlerServiceImpl service = new JaxWsHandlerServiceImplService().getJaxWsHandlerServiceImplPort();
        System.out.println(service.sayHello());

如果没有auth节点或者value(密码)不对就会抛出异常如:

	at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178)
	at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:111)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:108)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:78)
	at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:107)
	at $Proxy29.sayHello(Unknown Source)
	at org.sample.ws.client.ws.chap7.main.JaxWsHandlerServiceMain.main(JaxWsHandlerServiceMain.java:15)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值