Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

My Apache Camel application in Quarkus exits through 2 different ports when calling 2 SOAP WebServices in the same logic #5907

Open
cesarjv opened this issue Mar 21, 2024 · 6 comments

Comments

@cesarjv
Copy link

cesarjv commented Mar 21, 2024

I am currently working on a service using Apache Camel and Quarkus, in which I must call 2 SOAP Webservices, one that allows me to obtain a session id (called LGI Command) and the next allows me to consult the information from a mobile number. associated with it (Called LST_DYNSUB Command), passing the session id previously obtained with the LGI Command. The question is that these 2 calls must be made through the same port due to the policies of the application to be called where the aforementioned SOAP interfaces are located, called UDB, the UDB only admits a valid session id in the LST_DYNSUB command if the same port through which the LGI Command.

Testing in Postman does not give me problems and it can be seen that when testing both SOAP interfaces there are no problems, however, when I come to develop my waterfall logic in my Apache Camel and Quarkus development, it can be observed at the destination log level (UDB) that is being sent through different ports.

Called in postman and where it is observed that both interfaces arrive through the same ports:

Sin título

Called from my microservice with Apache Camel and Quarkus where it is evident that it is arriving through a different port, even though it is within the same logic:

Sin título

I attach the logic of my Red Route in Apache Camel:

Class Rest Route

@ApplicationScoped
public class RestRoute extends RouteBuilder {

    private static final String SALIDA_MS = "Salida del MS ${exchangeProperty[bodyRs]}";
    private static final String MSG_EXCEPTION = "Descripcion de la Exception: ${exception.message}";

    private static final String DATE_LOG = "[${bean:BeanDate.getCurrentDateTime()}] ";
    @ConfigProperty(name = "client.url.udb")
    String urlUDB;

    @ConfigProperty(name = "path.openapi")
    String pathOpenapi;

    @ConfigProperty(name = "descripcion.servicio")
    String descriptionService;

    private ConfigureSsl configureSsl;

    private IGetCurrentDateTime getCurrentDateTime;

    public RestRoute() {
        getCurrentDateTime = new GetCurrentDateTime();
        TimeZone.setDefault(TimeZone.getTimeZone("GMT-4"));
        configureSsl = new ConfigureSsl();
    }
    @Override
    public void configure() throws Exception {

        BeanDate beanDate= new BeanDate();
        getContext().getRegistry().bind("BeanDate", beanDate);

        restConfiguration().bindingMode(RestBindingMode.json).dataFormatProperty("json.in.disableFeatures","FAIL_ON_UNKNOWN_PROPERTIES")
                .apiContextPath(pathOpenapi)
                .apiProperty("api.title","UdbLoginConnector")
                .apiProperty("api.description",descriptionService)
                .apiProperty("api-version","1.0.0")
                .apiProperty("cors","true");
        rest("/api/")
                .produces("application/json")
                .consumes("application/json")
                .post("/deviceStatusConnector")
                .type(Request.class)
                .param().name("Request").type(RestParamType.body).description("Parametros de Entradas")
                .required(true)
                .endParam()
                .outType(Response.class)
                .param().name("Response").type(RestParamType.body).description("Parametros de Salidas")
                .required(true)
                .endParam().to("direct:pipeline");

                from("direct:pipeline")
                        .doTry()
                            /*.to("bean-validator:validateRequest") */
                            .process(new DeviceStatusConnectorProcessorReq())
                            .log(DATE_LOG+"Datos de Entrada del MS: ${exchangeProperty[bodyRq]}")
                            .process(new UdbLgiCommandProcessorReq())
                            .log(DATE_LOG+"Datos de Entrada del WebService (SOAP) Comando-LGI UDB: ${exchangeProperty[wsRq]}")
                            .to(configureSsl.setupSSLContext(getCamelContext(), urlUDB))
                            .log(DATE_LOG+"Datos de Salida del el WebService (SOAP) Comando-LGI UDB: ${body}")
                            .process( new UdbLgiCommandProcessRes())
                            .log(DATE_LOG+"SessionId Obtenido Comando-LGI UDB: ${exchangeProperty[sessionId]}")
                            .log(DATE_LOG+"Codigo de Respuesta Comando-LGI UDB: ${exchangeProperty[resultCodeLgiCommand]}")
                            .log(DATE_LOG+"Descripcion de Respuesta Comando-LGI UDB: ${exchangeProperty[resultDescriptionLgiCommand]}")
                            .process(new UdbLstDynsubCommandProcessorReq())
                             .log(DATE_LOG+"Datos de Entrada del WebService (SOAP) Comando LST-DYNSUB: ${exchangeProperty[wsRq]}")
                            .log(DATE_LOG+"Header de Entrada del WebService (SOAP) Comando LST-DYNSUB: ${headers}")
                            .to(configureSsl.setupSSLContext(getCamelContext(), urlUDB))
                            .log(DATE_LOG+"Datos de Salida del WebService (SOAP) Comando LST-DYNSUB: ${body}")
                        .endDoTry();
    }
}

UdbLgiCommandProcessorReq

@Slf4j
@ApplicationScoped
public class UdbLgiCommandProcessorReq implements Processor{

	private final String usernameUdbLgiCommand = ConfigProvider.getConfig().getValue("username.udb.lgi.command", String.class);
	private final String passwordUdbLgiCommand = ConfigProvider.getConfig().getValue("password.udb.lgi.command", String.class);

	private final IUdbLgiCommandRequestMapping requestMapping;

	public UdbLgiCommandProcessorReq() {
		requestMapping = new UdbLgiCommandRequestMappingImpl();
	}
	
	@SuppressWarnings({ "deprecation", "unchecked", "rawtypes" })
	@Override
	public void process(Exchange exchange) throws Exception {

		/*log.info("Request Json Entrada: "+udbLoginConnectorJsonReq.toString()); */
		EnvelopeRqLgiCommand envelopeRqLgiCommand = requestMapping.toRequest(usernameUdbLgiCommand, passwordUdbLgiCommand);
		String xmlWsRq = new GenericXml().toXmlString(envelopeRqLgiCommand);
		/*log.info("Transformation to XML "+xmlWsRq); */
		exchange.setProperty("wsRq", xmlWsRq.replaceAll("[\n\t\r]", ""));
		exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/xml");
		exchange.getOut().setHeader(Exchange.HTTP_METHOD, "POST");
		exchange.getOut().setBody(xmlWsRq);
	}
}

UdbLstDynsubCommandProcessorReq

@Slf4j
@ApplicationScoped
public class UdbLstDynsubCommandProcessorReq implements Processor{


	private final IUdbLstDynsubCommandRequestMapping requestMapping;

	public UdbLstDynsubCommandProcessorReq() {
		requestMapping = new UdbLstDynsubCommandRequestMappingImpl();
	}
	
	@SuppressWarnings({ "deprecation", "unchecked", "rawtypes" })
	@Override
	public void process(Exchange exchange) throws Exception {

		/*log.info("Request Json Entrada: "+udbLoginConnectorJsonReq.toString()); */
		String sessionId=exchange.getProperty("sessionId", String.class);
		Request request =  exchange.getProperty("deviceStatusConnectorRq", Request.class);
		EnvelopeRqLstDynSubCommand envelopeRqLstDynSubCommand = requestMapping.toRequest(request.getUdbDeviceStatusConnectorRequest().getBodyRequest().getIsdn(), request.getUdbDeviceStatusConnectorRequest().getBodyRequest().getContent());
		String xmlWsRq = new GenericXml().toXmlString(envelopeRqLstDynSubCommand);
		/*log.info("Transformation to XML "+xmlWsRq); */
		exchange.setProperty("wsRq", xmlWsRq.replaceAll("[\n\t\r]", ""));
		exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/xml");
		exchange.getOut().setHeader(Exchange.HTTP_METHOD, "POST");
		exchange.getOut().setHeader(Exchange.HTTP_PATH, sessionId);
		exchange.getOut().setBody(xmlWsRq);
	}
}

pom.xml

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.tmve.subscriber</groupId>
    <artifactId>device-status-connector</artifactId>
    <version>1.0.0-DEV</version>
    <properties>
        <compiler-plugin.version>3.11.0</compiler-plugin.version>
        <maven.compiler.release>17</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
        <quarkus.platform.version>3.2.10.Final</quarkus.platform.version>
        <skipITs>true</skipITs>
        <surefire-plugin.version>3.0.0</surefire-plugin.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>${quarkus.platform.artifact-id}</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-camel-bom</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-rest-openapi</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-bean-validator</artifactId>
            <version>3.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-bean</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-direct</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-http</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-jaxb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-log</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-openapi-java</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-openapi</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>swagger-ui</artifactId>
            <version>4.11.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-opentelemetry</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-opentelemetry-exporter-otlp</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-jacoco</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-codegen-plugin</artifactId>
            <version>4.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.camel</groupId>
            <artifactId>camel-cxf-soap</artifactId>
            <version>3.19.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.platform.version}</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                            <goal>generate-code</goal>
                            <goal>generate-code-tests</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${compiler-plugin.version}</version>
                <configuration>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>4.0.3</version>
                <executions>
                    <execution>
                        <id>generate-sources</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <sourceRoot>${basedir}/src/main/java</sourceRoot>
                            <wsdlOptions>
                                <wsdlOption>
                                    <wsdl>${basedir}/src/main/resources/wsdl/HSS9860.wsdl</wsdl>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <configuration>
                    <systemPropertyVariables>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <systemPropertyVariables>
                        <native.image.path>${project.build.directory}/${project.build.finalName}-runner
                        </native.image.path>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <profile>
            <id>native</id>
            <activation>
                <property>
                    <name>native</name>
                </property>
            </activation>
            <properties>
                <skipITs>false</skipITs>
                <quarkus.package.type>native</quarkus.package.type>
            </properties>
        </profile>
    </profiles>
</project>

Does this have any logical explanation as to why it could be happening in Apache Camel and Quarkus?

@jamesnetherton
Copy link
Contributor

Maybe due to HTTP connection pooling, keep-alive etc?

What are you using as the HTTP client to interact with the SOAP services?

@cesarjv
Copy link
Author

cesarjv commented Mar 21, 2024

@jamesnetherton As an http client I am using POSTMAN to test SOAP interfaces

@jamesnetherton
Copy link
Contributor

@jamesnetherton As an http client I am using POSTMAN to test SOAP interfaces

I mean in your Camel application. What's sending the SOAP request?

@cesarjv
Copy link
Author

cesarjv commented Mar 21, 2024

This is what I sent in the 2 requests

COMANDO LGI

https://10.160.12.181:8001

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:lgi="http://www.huawei.com/HLR9820/LGI">
    <soapenv:Header/>
    <soapenv:Body>
        <lgi:LGI>
            <lgi:OPNAME>OPENG</lgi:OPNAME>
            <lgi:PWD>{{passwordUDB}}</lgi:PWD>
            <lgi:HLRSN>1</lgi:HLRSN>
        </lgi:LGI>
    </soapenv:Body>
</soapenv:Envelope>

COMANDO LST_DYNSUB

https://10.160.12.181:8001/sessionId

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:lst="http://www.huawei.com/HLR9820/LST_DYNSUB">
    <soapenv:Header/>
    <soapenv:Body>
        <lst:LST_DYNSUB>
            <lst:ISDN>xxxxxxxxx</lst:ISDN>
            <lst:CONTENT>0</lst:CONTENT>
        </lst:LST_DYNSUB>
    </soapenv:Body>
</soapenv:Envelope>

@jamesnetherton Do you require more details?

@ppalaga
Copy link
Contributor

ppalaga commented Mar 21, 2024

@cesarjv I understand that you are writing a SOAP client application calling two external SOAP endpoints. From what you have shown, it is not clear, how you send the request to those endpoints.
.to(configureSsl.setupSSLContext(getCamelContext(), urlUDB)) seems to be the part sending the request to the remote SOAP endpoint. Please have a look how is the remote address and port set. Is perhaps some loadbalancer (that sends round robin to several ports) between the client and service?

@cesarjv
Copy link
Author

cesarjv commented Mar 21, 2024

With these classes I send the application

The ConfigureSSL class is used to configure the call using SSL:

@Slf4j
@SuppressWarnings({})
@ApplicationScoped
public class ConfigureSsl {
	
	private final String password = ConfigProvider.getConfig().getValue("client.ssl.password", String.class);
	private final String resource = ConfigProvider.getConfig().getValue("client.ssl.resource", String.class);
	
	 public Endpoint setupSSLContext(CamelContext camelContext, String url) throws Exception {

	        KeyStoreParameters keyStoreParameters = new KeyStoreParameters();
	        keyStoreParameters.setResource(resource);
	        keyStoreParameters.setPassword(password);

	        KeyManagersParameters keyManagersParameters = new KeyManagersParameters();
	        keyManagersParameters.setKeyStore(keyStoreParameters);
	        keyManagersParameters.setKeyPassword(password);

	        TrustManagersParameters trustManagersParameters = new TrustManagersParameters();
	        trustManagersParameters.setKeyStore(keyStoreParameters);

	        SSLContextParameters sslContextParameters = new SSLContextParameters();
	        sslContextParameters.setKeyManagers(keyManagersParameters);
	        sslContextParameters.setTrustManagers(trustManagersParameters);

	        HttpComponent httpComponent = camelContext.getComponent("https", HttpComponent.class);
	        httpComponent.setSslContextParameters(sslContextParameters);
	        httpComponent.setX509HostnameVerifier(new AllowAllHostnameVerifier());

	        return httpComponent.createEndpoint(url);
	    }
}

The udbUrl variable refers to the IP variable that is called and is found in the properties:

ResRoute

    @ConfigProperty(name = "client.url.udb")
    String urlUDB;

application.properties

client.url.udb=${UBICATION_URL_UDB:https://10.160.12.181:8001?bridgeEndpoint=false&?throwExceptionOnFailure=false}

No, the SOAP external IP is not governed by a LoadBalancer, it is a unique IP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants