Couldn't Consume a WebService SOAP from Dynamics Nav server with JAVA SpringBooot

34 views Asked by At

I'm trying to consume a WebService Soap from dynamics Nav 2015 with Java SpringBoot ! this WebService asks for Credentials (username,password,domain). when i called my service SoapClientService to call the method TestConnection() in dynamics nav server:

@Service
public class SoapClientService extends WebServiceGatewaySupport {

    @Value("${soap.service.url}")
    private String serviceUrl;

    @Value("${nav.user}")
    private String navUser;

    @Value("${nav.password}")
    private String navPassword;

    @Value("${nav.domain}")
    private String navDomain;

    public String testConnection() {
        // Create request object
        TestConnection request = new TestConnection();

        // Add SOAP headers for authentication
        getWebServiceTemplate().setInterceptors(new ClientInterceptor[] {
                new ClientInterceptor() {
                    @Override
                    public boolean handleRequest(MessageContext messageContext)   {
                        TransportContext context = TransportContextHolder.getTransportContext();
                        WebServiceMessage message = messageContext.getRequest();
                        SoapHeader header = ((SoapMessage) message).getSoapHeader();

                        QName navUserHeader = new QName("urn:microsoft-dynamics-schemas/codeunit/ControlePreparation", "NavUser");
                        QName navPassHeader = new QName("urn:microsoft-dynamics-schemas/codeunit/ControlePreparation", "NavPass");
                        QName navDomainHeader = new QName("urn:microsoft-dynamics-schemas/codeunit/ControlePreparation", "NavDomain");

                        header.addHeaderElement(navUserHeader).setText(navUser);
                        header.addHeaderElement(navPassHeader).setText(navPassword);
                        header.addHeaderElement(navDomainHeader).setText(navDomain);

                        return true;
                    }

                    @Override
                    public boolean handleResponse(MessageContext messageContext) {
                        // Handle response if needed
                        return true;
                    }


                    @Override
                    public boolean handleFault(MessageContext messageContext)  {
                        // Handle fault if needed
                        return true;
                    }

                    @Override
                    public void afterCompletion(MessageContext messageContext, Exception ex) {
                        // Clean up resources if needed
                    }
                }

        });


    // Make SOAP call and receive response
    TestConnectionResult response = (TestConnectionResult) getWebServiceTemplate().marshalSendAndReceive(serviceUrl, request,
            new SoapActionCallback(
                    "urn:microsoft-dynamics-schemas/codeunit/ControlePreparation:TestConnection"
            ));

        // Process response
        if (response != null) {
            return response.getReturnValue();
        } else {
            return null; // Or handle null response as needed
        }
    }
}

with my restController:

@RestController
@RequestMapping("/api")
public class SoapController {

    @Autowired
    private SoapClientService soapClientService;

    @GetMapping("/test-connection")
    public ResponseEntity<String> testConnection() {
        try {
            String response = soapClientService.testConnection();
            if (response != null) {
                return ResponseEntity.ok(response);
            } else {
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                        .body("Failed to retrieve test connection response.");
            }
        } catch (HttpClientErrorException e) {
            return ResponseEntity.status(e.getStatusCode()).body("HTTP error occurred: " + e.getMessage());
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("An error occurred while processing the request: " + e.getMessage());
        }
    }
}

then when I send the request http://localhost:9090/api/test-connection I got: An error occurred while processing the request: Unknown JAXB exception

The Problem that i couldn't distanguish if the javax exception is caused by xml/marshalSendAndReceive method or is caused by the inability to authenticate to the URL itself...

I generated my Java classes from the ControlePreparation.wsdl file which i placed it in ressources/wsdl.

injecting the dependency:

<dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version> <!-- Version peut ĂȘtre diffĂ©rente -->
        </dependency>

and the plugin:

<plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.15.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <generatePackage>com.ticop.demo.soapApi</generatePackage>
                    <generateDirectory>${project.basedir}/src/main/java</generateDirectory>
                    <schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
                    <schemaIncludes>
                        <include>*.wsdl</include>
                    </schemaIncludes>
                    <args>
                        <arg>-wsdl</arg>
                    </args>
                </configuration>
            </plugin>

the method TestConnection() of dynamics Nav server i want to call was illustrated on two JAVA classes:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "TestConnection")
public class TestConnection {


}
and
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "returnValue"
})
@XmlRootElement(name = "TestConnection_Result")
public class TestConnectionResult {

    @XmlElement(name = "return_value", required = true)
    protected String returnValue;

    /**
     * Gets the value of the returnValue property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getReturnValue() {
        return returnValue;
    }

    /**
     * Sets the value of the returnValue property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setReturnValue(String value) {
        this.returnValue = value;
    }

} 

then i created my WebServiceConfig.java Class :

@Configuration
public class WebServiceConfig {

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        // this package must match the package in the <generatePackage> specified in
        // pom.xml
        marshaller.setContextPath("com.ticop.demo.soapApi");
        return marshaller;
    }

    @Bean
    public SoapClientService soapClientService(Jaxb2Marshaller marshaller) {
        SoapClientService client = new SoapClientService();
        client.setDefaultUri("http://172.16.8.191:7047/DynamicsNAV80/WS/FAD2014/Codeunit/ControlePreparation");
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        return client;
    }
}
0

There are 0 answers