英文:
Pass data from a SOAP handler to a webservice server Class
问题
以下是您提供的代码翻译部分:
@Component
public class EndPointHandler implements SOAPHandler<SOAPMessageContext> {
    private List<String> ssoToken;
    private Map<String, List<String>> headers;
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        Boolean isResponse = (Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!isResponse) {
            headers = ((Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS));
            if (headers != null) {
                if (!headers.get("SSOToken").get(0).isEmpty()) {
                    List<String> ssoToken = headers.get("SSOToken");
                    LOGGER.info(ssoToken.get(0));
                    this.ssoToken = ssoToken;
                } else {
                    LOGGER.error("SSO Token value cannot be empty");
                    return false;
                }
            }
        }
        return true;
    }
    public void setSSOToken() {
        headers.put("SSOToken", this.ssoToken);
    }
}
@Component
public class ConnectionManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class);
    @Autowired
    private EndPointHandler handler;
    private void establishConnection(String uri) throws FileNetIntegrationException {
        handler.ssoToken; //  --> I need SSO token here but the value is NULL;
    }
}
@Bean
public Endpoint endpoint(Bus bus) {
    EndpointImpl endpoint = new EndpointImpl(bus, changeServiceEndpoint);
    WebService ws = AnnotationUtils.findAnnotation(endpoint.getImplementorClass(), WebService.class);
    endpoint.setAddress("/" + ws.serviceName());
    endpoint.publish();
    SOAPBinding binding = (SOAPBinding) endpoint.getBinding();
    ArrayList<Handler> handlerChain = new ArrayList<>();
    handlerChain.add(new EndPointHandler());
    binding.setHandlerChain(handlerChain);
    return endpoint;
}
英文:
I have a Spring boot SOAP services with cxf, and my Consumers are passing me SSO token in http header.. I am able to retrieve the SSO token using JAX-WS handler. I am saving that SSO token into handler class level variable, and after control going through various classes it reaches to a point where I have to make a request to another service and have to pass the same SSO token, but in my Connection class the SSO token value is NULL.
@Component
public class EndPointHandler implements SOAPHandler<SOAPMessageContext> {
    private List<String> ssoToken;
    private Map<String, List<String>> headers;
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        Boolean isResponse = (Boolean) context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!isResponse) {
            headers = ((Map<String, List<String>>) context.get(MessageContext.HTTP_REQUEST_HEADERS));
            if (headers != null) {
                if (!headers.get("SSOToken").get(0).isEmpty()) {
                    List<String> ssoToken = headers.get("SSOToken");
                    LOGGER.info(ssoToken.get(0));
                    this.ssoToken = ssoToken;
                } else {
                    LOGGER.error("SSO Token value cannot be empty");
                    return false;
                }
            }
        }
        return true;
    }
    public void setSSOToken() {
        headers.put("SSOToken", this.ssoToken);
    }
}
In my Connection class I have to set this SSO token as a header and make a call to another service but SSO token value is NULL.
Connection Class:
@Component
public class ConnectionManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class);
    @Autowired
    private EndPointHandler handler;
    private void establishConnection(String uri) throws FileNetIntegrationException {
        handler.ssoToken; //  --> I need SSO token here but the value is NULL;
    }
}
This is how I set the handler chain in my WebServiceConfig class:
@Bean
public Endpoint endpoint(Bus bus) {
    EndpointImpl endpoint = new EndpointImpl(bus, changeServiceEndpoint);
    WebService ws = AnnotationUtils.findAnnotation(endpoint.getImplementorClass(), WebService.class);
    endpoint.setAddress("/" + ws.serviceName());
    endpoint.publish();
    SOAPBinding binding = (SOAPBinding) endpoint.getBinding();
    ArrayList<Handler> handlerChain = new ArrayList<>();
    handlerChain.add(new EndPointHandler());
    binding.setHandlerChain(handlerChain);
    return endpoint;
}
答案1
得分: 4
我认为,就在我发布了最后一段代码之后,我立刻找到了一个解决方案,当我注意到在将其添加到处理程序链时使用了 new EndPointHandler().. 我尝试使用 @Autowired,这对我起了作用。
英文:
I think, I got a solution right after posting the last piece of code here when I noticed that I used new EndPointHandler() while adding it into handler chain.. I tried using Autowired it and it worked for me.
答案2
得分: 2
<sub>*据我所知,`jax-ws`上下文和`spring-ws`上下文彼此不相交。因此,这不是一个解决方案,而是一个变通方法。作为另一种变通方法,您可以使用一些单例的[`synchronizedMap`][1],或者使用`jax-ws`的`Handler`将请求重定向到具有扩展API的另一个端点。*</sub>
---
### 使用JAX-WS处理程序访问SOAP消息的HTTP头
如果您为`JAX-WS`的`WebService`配置了[`SOAPHandler`][2],那么您可以访问HTTP头并将它们作为[`SOAPElement`][5]类型的字段传递到[`SOAPBody`][4]中,反之亦然。为此,您必须使用这些字段扩展消息POJO,并对其进行[`XmlElement`][6]注释。然后您可以从您的[`WebService`][3]中访问它们。
*注意:*如果您的动态生成的WSDL基于Java类,那么它也会发生变化。但无论如何,旧的请求和响应都会被接受,因为这些字段默认不是必需的。
---
**示例:** `UserService` - 输入消息有一个`String`类型的字段,输出消息有一个`int`类型的字段。让我们分别使用一个`String`类型的`ssoToken`字段扩展它们。我们将从传入消息的HTTP头中读取此令牌,并在传出消息的HTTP头中将其发送回去。
GetUserRequest.java:
```java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserRequest")
public class GetUserRequest {
    @XmlElement
    protected String ssoToken;
    @XmlElement(required = true)
    protected String name;
    // getters + setters + constructor
}
GetUserResponse.java:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserResponse")
public class GetUserResponse {
    @XmlElement
    protected String ssoToken;
    @XmlElement(required = true)
    protected int age;
    // getters + setters + constructor
}
UserServiceHandler.java
public class UserServiceHandler implements SOAPHandler<SOAPMessageContext> {
    @Override
    public boolean handleMessage(SOAPMessageContext soapMessageContext) {
        Boolean isResponse =
                (Boolean) soapMessageContext
                        .get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!isResponse) {
            // 请求消息
            return processIncomingMessage(soapMessageContext);
        } else {
            // 响应消息
            return processOutgoingMessage(soapMessageContext);
        }
    }
}
processIncomingMessage:
@SuppressWarnings("unchecked")
private boolean processIncomingMessage(SOAPMessageContext soapMessageContext) {
    Map<String, List<String>> headers =
            ((Map<String, List<String>>) soapMessageContext
                    .get(MessageContext.HTTP_REQUEST_HEADERS));
    if (headers == null || headers.isEmpty()) {
        return false;
    }
    List<String> ssoTokens = headers.get("SSOToken");
    if (ssoTokens == null || ssoTokens.size() != 1) {
        return false;
    }
    String ssoToken = ssoTokens.get(0);
    if (ssoToken == null || ssoToken.isEmpty()) {
        return false;
    }
    try {
        Iterator<Node> iterator =
                soapMessageContext.getMessage().getSOAPBody().getChildElements();
        while (iterator.hasNext()) {
            Node element = iterator.next();
            if (element.getNodeName().contains("getUserRequest")) {
                ((SOAPElement) element)
                        .addChildElement("ssoToken", element.getPrefix())
                        .setTextContent(ssoToken);
            }
        }
    } catch (SOAPException e) {
        e.printStackTrace();
        return false;
    }
    return true;
}
processOutgoingMessage:
@SuppressWarnings("unchecked")
private boolean processOutgoingMessage(SOAPMessageContext soapMessageContext) {
    Map<String, List<String>> headers =
            ((Map<String, List<String>>) soapMessageContext
                    .get(MessageContext.HTTP_RESPONSE_HEADERS));
    if (headers == null || headers.isEmpty()) {
        soapMessageContext
                .put(MessageContext.HTTP_RESPONSE_HEADERS, new HashMap<>());
        headers = ((Map<String, List<String>>) soapMessageContext
                .get(MessageContext.HTTP_RESPONSE_HEADERS));
    }
    try {
        Iterator<Node> iterator = soapMessageContext
                .getMessage().getSOAPBody().getChildElements();
        while (iterator.hasNext()) {
            Node element = iterator.next();
            if (element.getNodeName().contains("getUserResponse")) {
                Iterator<Node> iteratorResponse =
                        ((SOAPElement) element).getChildElements();
                while (iteratorResponse.hasNext()) {
                    Node childElement = iteratorResponse.next();
                    if (childElement.getNodeName().contains("ssoToken")) {
                        String ssoToken = childElement.getTextContent();
                        headers.put("SSOToken",
                                Collections.singletonList(ssoToken));
                        element.removeChild(childElement);
                    }
                }
            }
        }
    } catch (SOAPException e) {
        e.printStackTrace();
        return false;
    }
    return true;
}
UserService.java
@WebService(endpointInterface = "com.example.UserPort",
        serviceName = "UserService")
@HandlerChain(file="handler-chain.xml")
public class UserService implements UserPort {
    public GetUserResponse getUser(GetUserRequest request) {
        GetUserResponse response = new GetUserResponse();
        response.setAge(23);
        response.setSsoToken(request.getSsoToken());
        return response;
    }
}
使用SoapUI进行测试:
请求头:
POST http://localhost:8080/ws/userService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Length: 296
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
请求消息:
<soapenv:Envelope
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:spr="http://example.com/jax-ws-sample">
    <soapenv:Header/>
    <soapenv:Body>
        <spr:getUserRequest>
            <spr:name>John</spr:name>
        </spr:getUserRequest>
    </soapenv:Body>
</soapenv:Envelope>
响应头:
HTTP/1.1 200 
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Type: text/xml;charset=utf-8
Transfer-Encoding:
<details>
<summary>英文:</summary>
<sub>*As far as I know, `jax-ws` context and `spring-ws` context don't intersect with each other. So this is not a solution but a workaround. As another workaround, you can use some singleton [`synchronizedMap`][1], or use a `jax-ws` `Handler` to redirect requests to another endpoint with extended api.*</sub>
---
### Access HTTP headers of SOAP messages using JAX-WS handler
If you have configured [`SOAPHandler`][2] for your `JAX-WS` [`WebService`][3], then you can access the HTTP headers and pass them on inside the [`SOAPBody`][4] as fields of the [`SOAPElement`][5] type, and vice versa. To do this you have to extend the messages POJOs with these fields annotated as [`XmlElement`][6]. Then you can access them from your [`WebService`][3].
*Note:* If you have a dynamically generated WSDL schema based on Java classes, then it changes too. But anyway, the old requests and responses are accepted, because these fields are not required by default.
---
**Example:** `UserService` - the incoming message has one field of `String` type and outgoing message has one field of `int` type. Let's extend each of them with one `ssoToken` field of `String` type. We'll read this token from HTTP headers of incoming message and send it back in HTTP headers of outgoing message.
GetUserRequest.java:
```java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserRequest")
public class GetUserRequest {
@XmlElement
protected String ssoToken;
@XmlElement(required = true)
protected String name;
// getters + setters + constructor
}
GetUserResponse.java:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "getUserResponse")
public class GetUserResponse {
    @XmlElement
    protected String ssoToken;
    @XmlElement(required = true)
    protected int age;
    // getters + setters + constructor
}
UserServiceHandler.java
public class UserServiceHandler implements SOAPHandler<SOAPMessageContext> {
    @Override
    public boolean handleMessage(SOAPMessageContext soapMessageContext) {
        Boolean isResponse =
                (Boolean) soapMessageContext
                        .get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!isResponse) {
            // Request message
            return processIncomingMessage(soapMessageContext);
        } else {
            // Response message
            return processOutgoingMessage(soapMessageContext);
        }
    }
}
processIncomingMessage:
@SuppressWarnings("unchecked")
private boolean processIncomingMessage(SOAPMessageContext soapMessageContext) {
    Map<String, List<String>> headers =
            ((Map<String, List<String>>) soapMessageContext
                    .get(MessageContext.HTTP_REQUEST_HEADERS));
    if (headers == null || headers.isEmpty()) {
        return false;
    }
    List<String> ssoTokens = headers.get("SSOToken");
    if (ssoTokens == null || ssoTokens.size() != 1) {
        return false;
    }
    String ssoToken = ssoTokens.get(0);
    if (ssoToken == null || ssoToken.isEmpty()) {
        return false;
    }
    try {
        Iterator<Node> iterator =
                soapMessageContext.getMessage().getSOAPBody().getChildElements();
        while (iterator.hasNext()) {
            Node element = iterator.next();
            if (element.getNodeName().contains("getUserRequest")) {
                ((SOAPElement) element)
                        .addChildElement("ssoToken", element.getPrefix())
                        .setTextContent(ssoToken);
            }
        }
    } catch (SOAPException e) {
        e.printStackTrace();
        return false;
    }
    return true;
}
processOutgoingMessage:
@SuppressWarnings("unchecked")
private boolean processOutgoingMessage(SOAPMessageContext soapMessageContext) {
    Map<String, List<String>> headers =
            ((Map<String, List<String>>) soapMessageContext
                    .get(MessageContext.HTTP_RESPONSE_HEADERS));
    if (headers == null || headers.isEmpty()) {
        soapMessageContext
                .put(MessageContext.HTTP_RESPONSE_HEADERS, new HashMap<>());
        headers = ((Map<String, List<String>>) soapMessageContext
                .get(MessageContext.HTTP_RESPONSE_HEADERS));
    }
    try {
        Iterator<Node> iterator = soapMessageContext
                .getMessage().getSOAPBody().getChildElements();
        while (iterator.hasNext()) {
            Node element = iterator.next();
            if (element.getNodeName().contains("getUserResponse")) {
                Iterator<Node> iteratorResponse =
                        ((SOAPElement) element).getChildElements();
                while (iteratorResponse.hasNext()) {
                    Node childElement = iteratorResponse.next();
                    if (childElement.getNodeName().contains("ssoToken")) {
                        String ssoToken = childElement.getTextContent();
                        headers.put("SSOToken",
                                Collections.singletonList(ssoToken));
                        element.removeChild(childElement);
                    }
                }
            }
        }
    } catch (SOAPException e) {
        e.printStackTrace();
        return false;
    }
    return true;
}
UserService.java
@WebService(endpointInterface = "com.example.UserPort",
        serviceName = "UserService")
@HandlerChain(file="handler-chain.xml")
public class UserService implements UserPort {
    public GetUserResponse getUser(GetUserRequest request) {
        GetUserResponse response = new GetUserResponse();
        response.setAge(23);
        response.setSsoToken(request.getSsoToken());
        return response;
    }
}
Testing with SoapUI:
Request headers:
POST http://localhost:8080/ws/userService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Length: 296
Host: localhost:8080
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Request message:
<soapenv:Envelope
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:spr="http://example.com/jax-ws-sample">
    <soapenv:Header/>
    <soapenv:Body>
        <spr:getUserRequest>
            <spr:name>John</spr:name>
        </spr:getUserRequest>
    </soapenv:Body>
</soapenv:Envelope>
Response headers:
HTTP/1.1 200 
SSOToken: 6cd506ac-738a-43ca-aee8-d13b78180605
Content-Type: text/xml;charset=utf-8
Transfer-Encoding: chunked
Date: Thu, 27 Aug 2020 15:54:33 GMT
Keep-Alive: timeout=20
Connection: keep-alive
Response message:
<S:Envelope 
        xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Header/>
    <S:Body>
        <getUserResponse xmlns="http://example.com/jax-ws-sample">
            <age>23</age>
        </getUserResponse>
    </S:Body>
</S:Envelope>
				通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论