apache / camel-k

Apache Camel K is a lightweight integration platform, born on Kubernetes, with serverless superpowers
https://camel.apache.org/camel-k
Apache License 2.0
848 stars 345 forks source link

Error occurred when deploying Route file containing Camel Soap using Camel #4850

Open halouprogramer opened 8 months ago

halouprogramer commented 8 months ago

What happened?

Hello Everyone Locally, the Quarkus application does not report an error, but when deploying the Route file using Camel I guess it has something to do with QuarkusClassLoader, but I don't know how to modify it.

JDK VERSION: 11 camel-k version: 1.10.1 camel version: 3.18

Steps to reproduce

  1. Use cxf-codegen-plugin 3.6.2 create Java Soap Entity
  2. Route File
    
    // camel-k: language=java
    // camel-k: env=TZ=Asia/Shanghai
    // camel-k: dependency=mvn:com.sun.xml.ws:jaxws-rt:2.3.3
    // camel-k: dependency=mvn:com.sun.xml.ws:rt:2.3.3
    // camel-k: dependency=camel-soap
    // camel-k: trait=container.name=demo
    // camel-k: resource=file:../../../target/demo.jar
    // camel-k: trait=jvm.classpath=/etc/camel/resources/demo.jar

import org.apache.camel.dataformat.soap.SoapDataFormat; import org.apache.camel.dataformat.soap.name.ServiceInterfaceStrategy; import org.apache.camel.quarkus.core.CamelQuarkusClassResolver;

public class DemoRoute extends RouteBuilder {

@Override
public void configure() throws Exception {  
    // Soap Convert
    SoapDataFormat soapDataFormat = new SoapDataFormat();
    soapDataFormat.setContextPath("wsdl");

    soapDataFormat.setElementNameStrategy(new ServiceInterfaceStrategy(
            getContext().getApplicationContextClassLoader().loadClass(DemoPortType.class.getName()) , true));

    // Source: Knative Event
    from("knative:event/demo")
        // ...
    .marshal(soapDataFormat)
    .to("direct:outbound_http");
}

}


3. Deploy
kamel run --name demo --profile Knative --property file:../../../biz.properties DemoRoute.java

### Relevant log output

```shell
Failed to start application: java.lang.IllegalArgumentException: The number of @WebParam annotations for Method syncUBREXCHANGE does not match the number of parameters. This is not supported.
    at org.apache.camel.dataformat.soap.name.ServiceInterfaceStrategy.getInInfo(ServiceInterfaceStrategy.java:122)
    at org.apache.camel.dataformat.soap.name.ServiceInterfaceStrategy.analyzeMethod(ServiceInterfaceStrategy.java:145)
    at org.apache.camel.dataformat.soap.name.ServiceInterfaceStrategy.analyzeServiceInterface(ServiceInterfaceStrategy.java:157)
    at org.apache.camel.dataformat.soap.name.ServiceInterfaceStrategy.<init>(ServiceInterfaceStrategy.java:58)
    at DemoRoute.configure(DemoRoute.java:133)
    at org.apache.camel.builder.RouteBuilder.checkInitialized(RouteBuilder.java:672)
    at org.apache.camel.builder.RouteBuilder.configureRoutes(RouteBuilder.java:618)
    at org.apache.camel.builder.RouteBuilder.addRoutesToCamelContext(RouteBuilder.java:554)
    at org.apache.camel.impl.engine.AbstractCamelContext.addRoutes(AbstractCamelContext.java:1178)
    at org.apache.camel.main.RoutesConfigurer.addDiscoveredRoutes(RoutesConfigurer.java:237)
    at org.apache.camel.main.RoutesConfigurer.configureRoutes(RoutesConfigurer.java:212)
    at org.apache.camel.quarkus.main.CamelMain.configureRoutes(CamelMain.java:70)
    at org.apache.camel.main.BaseMainSupport.postProcessCamelContext(BaseMainSupport.java:637)
    at org.apache.camel.quarkus.main.CamelMain.initCamelContext(CamelMain.java:116)
    at org.apache.camel.quarkus.main.CamelMain.doInit(CamelMain.java:86)
    at org.apache.camel.support.service.BaseService.init(BaseService.java:83)
    at org.apache.camel.quarkus.main.CamelMain.startEngine(CamelMain.java:137)
    at org.apache.camel.quarkus.main.CamelMainRuntime.start(CamelMainRuntime.java:49)
    at org.apache.camel.quarkus.core.CamelBootstrapRecorder.start(CamelBootstrapRecorder.java:45)
    at io.quarkus.deployment.steps.CamelBootstrapProcessor$boot173480958.deploy_0(Unknown Source)
    at io.quarkus.deployment.steps.CamelBootstrapProcessor$boot173480958.deploy(Unknown Source)
    at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
    at io.quarkus.runtime.Application.start(Application.java:101)
    at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:110)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:70)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:43)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:123)
    at io.quarkus.runner.GeneratedMain.main(Unknown Source)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:61)
    at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:32)

Camel K version

Camel K Client Red Hat 1.10.1 Camel K Operator 1.10.1

squakez commented 8 months ago

It seems a runtime error caused by camel-soap component [1]. You mention, this is not happening when running with Camel Quarkus. Can you please verify what version of Camel Quarkus are you using? Can you also repeat the test with Camel Quarkus 2.13.3 which is the one used in 1.10.1 runtime?

[1] https://github.com/apache/camel/blob/e2ea12fdd29d8d446ec7b3fdf7c6db2147e196b4/components/camel-soap/src/main/java/org/apache/camel/dataformat/soap/name/ServiceInterfaceStrategy.java#L123

halouprogramer commented 8 months ago

I built a similar application using Camel Quarkus 2.3.0, and it still doesn't report any errors when starting locally. However, when deploying the application to OpenShift using Kamel, it reports an error during the startup phase. Here is the example: https://github.com/halouprogramer/camel-soap-demo

The deployment process is as follows:

mvn clean compiler:compile jar:jar kamel run --name camel-soap-demo DemoRoute.java

Could it be a problem with the ClassLoader? The loader used by the local Quarkus is QuarkusClassLoader:Quarkus Base Runtime ClassLoader: DEV@55fe41ea. The loader printed after deployment to OpenShift is io.quarkus.bootstrap.runner.RunnerClassLoader@7fbe847c.

halouprogramer commented 8 months ago

The problem lies in this line. https://github.com/apache/camel/blob/e2ea12fdd29d8d446ec7b3fdf7c6db2147e196b4/components/camel-soap/src/main/java/org/apache/camel/dataformat/soap/name/ServiceInterfaceStrategy.java#L115C21-L115C31 annotation instanceof WebParam The local Quarkus startup result is true, but it is false when deployed to OpenShift by Kamel.

squakez commented 8 months ago

Yeah, likely this is because in Camel K Runtime, the routes are loaded dynamically, hence they have a different classloader. I am not sure there is an easy way to solve this with the actual model. @lburgazzoli wdyt?

lburgazzoli commented 8 months ago

I don't think the classloader should make a difference in this case, I would first check if the version of camel-k supports the jakarta namespace or not.

halouprogramer commented 8 months ago

I will try replacing it with jakarta.

But I would like to add one thing.

Method 1: When I use the following method, the Route can start normally. 1.Upload the camel-soap-demo.jar package to Nexus. 2.Import the dependency using the dependency method, // camel-k: dependency=mvn:com.demo:camel-soap-demo:1.0.0

Method 2: Using the following method will result in the aforementioned exception, and the application fails to start. // camel-k: resource=file:../../../target/camel-soap-demo.jar // camel-k: trait=jvm.classpath=/etc/camel/resources/camel-soap-demo.jar

I don't know the difference between these two methods. I hope to receive further advice.

lburgazzoli commented 8 months ago

I think the difference is that with an explicit dependency, any additional transitive dependency is also added to the classpath, whereas the second method, won't probably do so and the dependency is only added at runtime.

you can compare the integration kit generated by the two options and see if there is any difference.

halouprogramer commented 8 months ago

I think the difference is that with an explicit dependency, any additional transitive dependency is also added to the classpath, whereas the second method, won't probably do so and the dependency is only added at runtime.

you can compare the integration kit generated by the two options and see if there is any difference.

The second method indeed cannot search for any information related to camel-soap-demo.jar in the integration kit. However, I still don't understand the exact reason for the above exception.

halouprogramer commented 8 months ago

I don't think the classloader should make a difference in this case, I would first check if the version of camel-k supports the jakarta namespace or not.

The version of kamel-k I am using does not support jakarta namespace. The jakarta namespace can only be used in camel-soap version 4.0.0 and above, which means the JDK version may also need to be upgraded to JDK17. At the same time, I am also worried that the same situation will occur after the upgrade.

https://github.com/apache/camel/blob/camel-4.0.x/components/camel-soap/src/main/java/org/apache/camel/dataformat/soap/name/ServiceInterfaceStrategy.java#L28

I don't know if there are any other solutions under the current version environment.

squakez commented 7 months ago

I have the feeling this one depends on #4639 It looks like the resources are used correctly when the dependency is provided at build time (via -d option) but not when it happens at runtime (via -t jvm option).