Saturday, 29 January 2022

This week 1/2022 - Spring WS client

In this post I'd like to present my reflection after implementing Web Service client in Spring WS. A time ago when I have been implementing a client or a service I did that in Apache CXF but this time to archive organisational standards for new implementation I used Spring WS.

Comparing to Apache CXF, from my perspective Spring WS is easier. It needs only to generate a model classes from WSDL or XSD file. This is important because Spring WS is contact-first implementation (only transform XSD/WSDL to classes, do not support other direction) to avoid incompatibles between different languages and implementations. 

I was a bit surprised that I don't create any Webservice Stub for my client. Only a model classes.

Below are presented a configuration of beans. The wsClient where I injected marshaller and defined interceptors. In my case I created interceptor to signature and encrypt message. 

In method signatureInterceptor is whole interceptor configuration.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Bean
public Client wsClient(final Jaxb2Marshaller marshaller) throws Exception {
    final Client client = new Client("https://example.com/webservice_uri");
    client.setMarshaller(marshaller);
    client.setUnmarshaller(marshaller);
    client.setInterceptors(new ClientInterceptor[]{signatureInterceptor()});
    return client;
}

private ClientInterceptor signatureInterceptor() throws Exception {
    Wss4jSecurityInterceptor wss4jSecurityInterceptor = new Wss4jSecurityInterceptor();
    wss4jSecurityInterceptor.setEnableSignatureConfirmation(true);
    wss4jSecurityInterceptor.setSecurementActions("Signature Encrypt");
    wss4jSecurityInterceptor.setSecurementUsername("securementUsername");
    wss4jSecurityInterceptor.setSecurementPassword("securementPassword");
    wss4jSecurityInterceptor.setSecurementSignatureCrypto(getCryptoFactoryBean().getObject());

    wss4jSecurityInterceptor.setSecurementEncryptionUser("encryption-user");
    wss4jSecurityInterceptor.setSecurementEncryptionParts("{Content}{https://example.com/service}getResponse");
    wss4jSecurityInterceptor.setSecurementEncryptionCrypto(getCryptoFactoryBean().getObject());

    return wss4jSecurityInterceptor;
}

@Bean
public CryptoFactoryBean getCryptoFactoryBean() throws IOException {
    CryptoFactoryBean cryptoFactoryBean = new CryptoFactoryBean();
    cryptoFactoryBean.setKeyStorePassword("testKeyStorePassword");
    cryptoFactoryBean.setKeyStoreLocation(new ClassPathResource("some.jks"));
    return cryptoFactoryBean;
}

@Bean
public Jaxb2Marshaller marshaller() {
    final Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setClassesToBeBound(Request.class, Response.class);
    return marshaller;
}


Implementation of ws client extends WebServiceGatewaySupport and implements my custom method "service". In those method I call webService template with uri and request object.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Client extends WebServiceGatewaySupport {

    private final String uri;

    public Client(String uri) {
        this.uri = uri;
    }

    public Response service() {
        return (Response)getWebServiceTemplate()
                .marshalSendAndReceive(uri, new Request());
    }
}

In response I got object which I had to cast to expected type.

To use the model in JDK17 I  generated it by maven plugin org.jvnet.jaxb2.maven2:maven-jaxb2-plugin but it is possible to use others. 

Below an example of plugin configuration to generate a model form wsdl file with possible additional annotations defined in wsdl or binding file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.14.0</version>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.6</version>
        </dependency>
    </dependencies>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <schemaLanguage>WSDL</schemaLanguage>
        <schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
        <schemaIncludes>
            <include>*.wsdl</include>
        </schemaIncludes>
        <args>
            <arg>-Xannotate</arg>
         </args>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2_commons</groupId>
                <artifactId>jaxb2-basics</artifactId>
                <version>1.11.1</version>
            </plugin>
            <plugin>
                <groupId>org.jvnet.jaxb2_commons</groupId>
                <artifactId>jaxb2-basics-annotate</artifactId>
                <version>1.11.0</version>
            </plugin>
        </plugins>
    </configuration>
</plugin>

And here possible (some of them required) dependences.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
        <version>5.3.15</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-core</artifactId>
        <version>3.1.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-security</artifactId>
        <version>3.1.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.ws</groupId>
        <artifactId>spring-ws-support</artifactId>
        <version>3.1.2</version>
    </dependency>
    <dependency>
        <groupId>wsdl4j</groupId>
        <artifactId>wsdl4j</artifactId>
        <version>1.6.3</version>
    </dependency>
    <dependency>
        <groupId>org.jvnet.jaxb2_commons</groupId>
        <artifactId>jaxb2-basics-runtime</artifactId>
        <version>1.11.1</version>
    </dependency>
</dependencies>


Resources:

[1] - Wss4jSecurityInterceptor java doc

[2] - Baeldung Example

[3] - spring ws

 

No comments:

Post a Comment