Axis2:在 AxisFault 之后重试 Web 服务调用

Axis2: retry web service call after AxisFault

环境:Ubuntu x86_64, JDK 1.7.0_80, Tomcat 7.0.64

我正在处理一些 Axis2 网络服务,我希望能够在网络服务调用后捕获 AxisFault 异常(例如,当抛出 HTTP 404、500 或 SSL 错误时),执行一些任务 (为了尝试自动解决任何配置问题)并只重试一次相同的 Web 服务请求。我知道 Axis2 阶段和处理程序以及我们如何在 InFault- 或 OutFaultFlow 阶段触发处理程序,但我认为它不符合目的,因为我只想执行一次重试,例如,如果我收到重试时的另一个 AxisFault,我希望它升级并让整个请求失败(这意味着系统在第一次失败后 self-configure 的努力不足以解决问题,因此系统管理员干预是需要的)。我认为使用处理程序会使请求进入无限循环,以防 self-configuration 无法解决问题。不过,我试过了,但找不到执行重试的方法。因此,我正在尝试在触发请求的代码中执行通常的 try/catch。

在我的 Stub class 中,我创建了 ServiceClient 及其选项,必要的 headers 然后我执行请求。这是代码的相关部分:

public class RespondingGateway_ServiceStub extends org.apache.axis2.client.Stub {


       private void populateAxisService() {

        // creating the Service with a unique name
        _service = new org.apache.axis2.description.AxisService("RespondingGateway_Service" + getUniqueSuffix());
        addAnonymousOperations();

        // creating the operations
        org.apache.axis2.description.AxisOperation __operation;
        _operations = new org.apache.axis2.description.AxisOperation[1];
        __operation = new org.apache.axis2.description.OutInAxisOperation();
        __operation.setName(new javax.xml.namespace.QName(XCPDConstants.SOAP_HEADERS.NAMESPACE_URI, XCPDConstants.SOAP_HEADERS.NAMESPACE_REQUEST_LOCAL_PART));
        _service.addOperation(__operation);
        _operations[0] = __operation;

        }

        // populates the faults
        private void populateFaults() {
        }

        /**
         * Constructor that takes in a configContext
         */
        public RespondingGateway_ServiceStub(org.apache.axis2.context.ConfigurationContext configurationContext, String targetEndpoint) {
            this(configurationContext, targetEndpoint, false);
        }

        /**
         * Constructor that takes in a configContext and useseperate listner
         */
        public RespondingGateway_ServiceStub(org.apache.axis2.context.ConfigurationContext configurationContext, String targetEndpoint, boolean useSeparateListener) {
            // To populate AxisService
            populateAxisService();
            populateFaults();
            try {
                _serviceClient = new org.apache.axis2.client.ServiceClient(configurationContext, _service);
            } catch (AxisFault ex) {
                throw new RuntimeException(ex);
            }

            _serviceClient.getOptions().setTo(new org.apache.axis2.addressing.EndpointReference(targetEndpoint));
            _serviceClient.getOptions().setUseSeparateListener(useSeparateListener);

            _serviceClient.getOptions().setTimeOutInMilliSeconds(180000); //Wait time after which a client times out in a blocking scenario: 3 minutes

            // Set the soap version
            _serviceClient.getOptions().setSoapVersionURI(org.apache.axiom.soap.SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);

            MultiThreadedHttpConnectionManager multiThreadedHttpConnectionManager = new MultiThreadedHttpConnectionManager();

            HttpConnectionManagerParams params = new HttpConnectionManagerParams();
            params.setDefaultMaxConnectionsPerHost(20);
            multiThreadedHttpConnectionManager.setParams(params);
            HttpClient httpClient = new HttpClient(multiThreadedHttpConnectionManager);

            this._getServiceClient().getServiceContext().getConfigurationContext().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, false);
            this._getServiceClient().getServiceContext().getConfigurationContext().setProperty(HTTPConstants.CACHED_HTTP_CLIENT, httpClient);
            this._getServiceClient().getServiceContext().getConfigurationContext().setProperty(HTTPConstants.AUTO_RELEASE_CONNECTION, false);
        }

    public org.hl7.v3.PRPAIN201306UV02 respondingGateway_PRPA_IN201305UV02(PRPAIN201305UV02 pRPA_IN201305UV02, Assertion idAssertion) {

        org.apache.axis2.client.OperationClient operationClient = _serviceClient.createClient(_operations[0].getName());

        /* set the message context with that soap envelope */
        org.apache.axis2.context.MessageContext messageContext = new org.apache.axis2.context.MessageContext();
        messageContext.setEnvelope(env);

        /* add the message contxt to the operation client */
        operationClient.addMessageContext(messageContext);

        try {
            operationClient.execute(true);
        } catch (AxisFault e) {
        // perform internal tasks
        // retry the request
        // if we get another AxisFault we just let it escalate
        }
    }

使用此代码,我能够捕获 AxisFault 并执行内部任务。但是后来我不知道如何执行重试。我尝试使用 Axis2 API,包括再次调用 catch 块内的 operationClient.execute(true) 但没有成功:

try {
        operationClient.execute(true);
    } catch (AxisFault e) {
       operationClient.complete(messageContext);
       LOG.debug("Adding message context again");
       messageContext.resetExecutedPhases();
       operationClient.addMessageContext(messageContext);
       LOG.debug("Executing");
       operationClient.execute(true);
       LOG.debug("Successfully retried the operation!");

我收到以下错误:

ERROR 2017-04-19 12:59:03,832 eu.epsos.pt.cc.ClientConnectorServiceMessageReceiverInOut invokeBusinessLogic.385  - A message was added that is not valid. However, the operation context was complete.
java.lang.RuntimeException: A message was added that is not valid. However, the operation context was complete.
    at tr.com.srdc.epsos.ws.xcpd.client.RespondingGateway_ServiceStub.respondingGateway_PRPA_IN201305UV02(RespondingGateway_ServiceStub.java:445)
    at tr.com.srdc.epsos.ws.xcpd.client.RespondingGateway_RequestSender.sendRequest(RespondingGateway_RequestSender.java:80)
    at tr.com.srdc.epsos.ws.xcpd.client.RespondingGateway_RequestSender.respondingGateway_PRPA_IN201305UV02(RespondingGateway_RequestSender.java:69)
    at eu.epsos.pt.ws.client.xcpd.XcpdInitGateway.patientDiscovery(XcpdInitGateway.java:59)
    at eu.epsos.pt.cc.stub.IdentificationService.findIdentityByTraits(IdentificationService.java:72)
    at eu.epsos.pt.cc.ClientConnectorServiceSkeleton.queryPatient(ClientConnectorServiceSkeleton.java:107)
    at eu.epsos.pt.cc.ClientConnectorServiceMessageReceiverInOut.invokeBusinessLogic(ClientConnectorServiceMessageReceiverInOut.java:215)
    at org.apache.axis2.receivers.AbstractInOutMessageReceiver.invokeBusinessLogic(AbstractInOutMessageReceiver.java:40)
    at org.apache.axis2.receivers.AbstractMessageReceiver.receive(AbstractMessageReceiver.java:114)
    at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:181)
    at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:172)
    at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:146)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.axis2.AxisFault: A message was added that is not valid. However, the operation context was complete.
    at org.apache.axis2.description.OutInAxisOperation.addMessageContext(OutInAxisOperation.java:78)
    at org.apache.axis2.context.OperationContext.addMessageContext(OperationContext.java:218)
    at org.apache.axis2.description.AxisOperation.registerOperationContext(AxisOperation.java:286)
    at org.apache.axis2.description.OutInAxisOperationClient.addMessageContext(OutInAxisOperation.java:132)
    at tr.com.srdc.epsos.ws.xcpd.client.RespondingGateway_ServiceStub.respondingGateway_PRPA_IN201305UV02(RespondingGateway_ServiceStub.java:302)
    ... 33 more

我尝试寻找解决方案但没有成功。我认为这应该是重新设置 Axis2 内部 Web 服务状态和阶段的问题,但我不知道如何解决这个问题。

我找到了解决方案。基本上,我必须创建一个新的 OperationClient、SOAPEnvelope 和 MessageContext 并再次执行请求:

try {
    operationClient.execute(true);
} catch (AxisFault e) {
    LOG.error("Axis Fault error: " + e.getMessage());

    /* we need a new OperationClient, otherwise we'll face the error "A message was added that is not valid. However, the operation context was complete." */
    OperationClient newOperationClient = _serviceClient.createClient(_operations[0].getName());
    newOperationClient.getOptions().setAction(XCPDConstants.SOAP_HEADERS.REQUEST_ACTION);
    newOperationClient.getOptions().setExceptionToBeThrownOnSOAPFault(true);
    addPropertyToOperationClient(newOperationClient, org.apache.axis2.description.WSDL2Constants.ATTR_WHTTP_QUERY_PARAMETER_SEPARATOR, "&");

    SOAPFactory newSoapFactory = getFactory(newOperationClient.getOptions().getSoapVersionURI());

    org.apache.axiom.soap.SOAPEnvelope newEnv;
    newEnv = toEnvelope(newSoapFactory,
                pRPA_IN201305UV02,
                optimizeContent(new javax.xml.namespace.QName(XCPDConstants.SOAP_HEADERS.NAMESPACE_URI, XCPDConstants.SOAP_HEADERS.NAMESPACE_REQUEST_LOCAL_PART)));

    _serviceClient.addHeadersToEnvelope(newEnv);

    /* we create a new Message Context with the new SOAP envelope */
    org.apache.axis2.context.MessageContext newMessageContext = new org.apache.axis2.context.MessageContext();
    newMessageContext.setEnvelope(newEnv);

    /* add the new message contxt to the new operation client */
    newOperationClient.addMessageContext(newMessageContext);
    /* we retry the request */
    newOperationClient.execute(true);
}