Matheus Moreira
Matheus Moreira

Reputation: 2388

Apache CXF and Apache Camel: the given SOAPAction does not match an operation

I'm trying to walk through the Camel Report Incident tutorial and am stuck at the end of part 5. When I try to run the unit test it fails with the message The given SOAPAction http://reportincident.example.camel.apache.org/ReportIncident does not match an operation.

I saw a similar question where the problem was that the declared soapAction attribute on the WSDL file had a different value from the actual SOAP request. This does not seem to be my case. Any ideas about what is going wrong? Thanks in advance.

reportIncident.wsdl

<?xml version="1.0" encoding="ISO-8859-1"?>
<wsdl:definitions 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://reportincident.example.camel.apache.org" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    targetNamespace="http://reportincident.example.camel.apache.org">

    <!-- Type definitions for input- and output parameters for webservice -->
    <wsdl:types>
        <xs:schema targetNamespace="http://reportincident.example.camel.apache.org">
            <xs:element name="inputReportIncident">
                <xs:complexType name="inputReportIncident">
                    <xs:sequence>
                        <xs:element type="xs:string" name="incidentId" />
                        <xs:element type="xs:string" name="incidentDate" />
                        <xs:element type="xs:string" name="givenName" />
                        <xs:element type="xs:string" name="familyName" />
                        <xs:element type="xs:string" name="summary" />
                        <xs:element type="xs:string" name="details" />
                        <xs:element type="xs:string" name="email" />
                        <xs:element type="xs:string" name="phone" />
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
            <xs:element name="outputReportIncident">
                <xs:complexType name="outputReportIncident">
                    <xs:sequence>
                        <xs:element type="xs:string" name="code" />
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:schema>
    </wsdl:types>

    <!-- Message definitions for input and output -->
    <wsdl:message name="inputReportIncident">
        <wsdl:part name="parameters" element="tns:inputReportIncident" />
    </wsdl:message>
    <wsdl:message name="outputReportIncident">
        <wsdl:part name="parameters" element="tns:outputReportIncident" />
    </wsdl:message>

    <!-- Port (interface) definitions -->
    <wsdl:portType name="ReportIncidentEndpoint">
        <wsdl:operation name="ReportIncident">
            <wsdl:input message="tns:inputReportIncident" />
            <wsdl:output message="tns:outputReportIncident" />
        </wsdl:operation>
    </wsdl:portType>

    <!-- Port bindings to transports and encoding - HTTP, document literal 
        encoding is used -->
    <wsdl:binding name="ReportIncidentBinding" type="tns:ReportIncidentEndpoint">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="ReportIncident">
            <soap:operation soapAction="http://reportincident.example.camel.apache.org/ReportIncident" style="document" />
            <wsdl:input>
                <soap:body parts="parameters" use="literal" />
            </wsdl:input>
            <wsdl:output>
                <soap:body parts="parameters" use="literal" />
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>

    <!-- Service definition -->
    <wsdl:service name="ReportIncidentService">
        <wsdl:port name="ReportIncidentPort" binding="tns:ReportIncidentBinding">
            <soap:address location="http://reportincident.example.camel.apache.org" />
        </wsdl:port>
    </wsdl:service>

</wsdl:definitions>

route definition (inside a RouteBuilder subclass)

OutputReportIncident ok = new OutputReportIncident();
ok.setCode("0");

// endpoint to our CXF webservice
String cxfEndpoint = "cxf://http://localhost:8080/part-five/webservices/incident"
        + "?serviceClass=org.apache.camel.example.reportincident.ReportIncidentEndpoint"
        + "&wsdlURL=reportIncident.wsdl";

// first part from the webservice -> file backup
from(cxfEndpoint)
    // we need to convert the CXF payload to InputReportIncident that FilenameGenerator and velocity expects
    .convertBodyTo(InputReportIncident.class)
    // then set the file name using the FilenameGenerator bean
    .setHeader("CamelFileName", BeanLanguage.bean(FilenameGenerator.class, "generateFilename"))
    // transform the message using velocity to generate the mail message
    .to("velocity:mailBody.vm")
    // and store the file   
    .to("file://target/subfolder")
    // return OK as response
    // usando transformação!
    .transform(constant(ok));

pom.xml (wsdl2java is used to generate Java files from WSDL)

<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>2.13.0</version>
    <executions>
        <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
                <sourceRoot>${project.build.directory}/generated/src/main/java</sourceRoot>
                <wsdlOptions>
                    <wsdlOption>
                        <wsdl>${basedir}/src/main/resources/reportIncident.wsdl</wsdl>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2java</goal>
            </goals>
        </execution>
    </executions>
</plugin>

test code

package org.apache.camel.example.reportincident;

import static org.junit.Assert.*;

import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.junit.Test;
import org.jvnet.mock_javamail.Mailbox;

public class ReportIncidentRoutesTest {

    // should be the same address as we have in our route
    private static String ADDRESS = "http://localhost:8080/part-five/webservices/incident";

    private CamelContext context;

    @Test
    public void testRendportIncident() throws Exception {
        // start camel
        startCamel();

        // assert mailbox is empty before starting
        Mailbox inbox = Mailbox.get("[email protected]");
        assertEquals("Should not have mails", 0, inbox.size());

        // create input parameter
        InputReportIncident input = new InputReportIncident();
        input.setIncidentId("123");
        input.setIncidentDate("2008-08-18");
        input.setGivenName("Claus");
        input.setFamilyName("Ibsen");
        input.setSummary("Bla");
        input.setDetails("Bla bla");
        input.setEmail("[email protected]");
        input.setPhone("0045 2962 7576");

        // create the webservice client and send the request
        ReportIncidentEndpoint client = createCXFClient();
        OutputReportIncident out = client.reportIncident(input);

        // assert we got a OK back
        assertEquals("0", out.getCode());

        // let some time pass to allow Camel to pickup the file and send it as an email
        Thread.sleep(3000);

        // assert mail box
        assertEquals("Should have got 1 mail", 1, inbox.size());

        // stop camel
        context.stop();
    }

    private void startCamel() throws Exception {
        context = new DefaultCamelContext();
        context.disableJMX();
        context.addRoutes(new ReportIncidentRoutes());
        context.start();
    }

    private ReportIncidentEndpoint createCXFClient() {
        // we use CXF to create a client for us as its easier than JAXWS and works
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(ReportIncidentEndpoint.class);
        factory.setAddress(ADDRESS);
        return (ReportIncidentEndpoint) factory.create();
    }

}

Upvotes: 0

Views: 4549

Answers (1)

Willem Jiang
Willem Jiang

Reputation: 3291

I think you just need to pass the WSDL url to the JaxWsProxyFactoryBean and it can take care of the soap action for you.

Please change the ReportIncidentRoutesTest.createCXFClient() like this

private ReportIncidentEndpoint createCXFClient() {
        // we use CXF to create a client for us as its easier than JAXWS and works
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(ReportIncidentEndpoint.class);
        factory.setWsdlURL("reportIncident.wsdl");
        factory.setAddress(ADDRESS);
        return (ReportIncidentEndpoint) factory.create();
    }

Upvotes: 1

Related Questions