Skip to content

refactor(wsdl): streamline WSDL handling, improve logging, and adjust…#2571

Merged
predic8 merged 22 commits into
masterfrom
soapproxy-wsdlinterceptor-yaml-fix
Jan 12, 2026
Merged

refactor(wsdl): streamline WSDL handling, improve logging, and adjust…#2571
predic8 merged 22 commits into
masterfrom
soapproxy-wsdlinterceptor-yaml-fix

Conversation

@predic8

@predic8 predic8 commented Jan 8, 2026

Copy link
Copy Markdown
Member

… interceptor flow

  • Removed unused fields blockRequest and blockResponse in AbstractProxy.
  • Simplified log.debug messages in WSDLPublisherInterceptor.
  • Adjusted interceptor execution order in SOAPProxy by adding WSDLPublisherInterceptor to the end.
  • Changed @MCElement for WSDLInterceptor to include it in the flow.
  • Improved readability with formatted and repositioned imports for notFound.

Summary by CodeRabbit

  • New Features

    • Added path-based WSDL service location rewriting capability for customizing endpoint addresses in WSDL documents.
    • Introduced SOAP proxy tutorial configurations demonstrating setup, WSDL rewriting, and message validation scenarios.
  • Tests

    • Added tutorial tests validating SOAP proxy functionality including WSDL access, service invocation, and message validation.

✏️ Tip: You can customize this high-level summary in your review settings.

… interceptor flow

- Removed unused fields `blockRequest` and `blockResponse` in `AbstractProxy`.
- Simplified `log.debug` messages in `WSDLPublisherInterceptor`.
- Adjusted interceptor execution order in `SOAPProxy` by adding `WSDLPublisherInterceptor` to the end.
- Changed `@MCElement` for `WSDLInterceptor` to include it in the flow.
- Improved readability with `formatted` and repositioned imports for `notFound`.
@coderabbitai

coderabbitai Bot commented Jan 8, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR introduces WSDL path rewriting capabilities to the Membrane API Gateway. It adds path-based rewriting in WSDLInterceptor, refactors SOAPProxy to use centralized WSDL utilities, updates launcher scripts to auto-discover Membrane installation, and includes comprehensive tutorial tests and configurations for SOAP proxy workflows with WSDL rewriting and validation.

Changes

Cohort / File(s) Summary
WSDL Path Rewriting Core
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java, core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java
Added path field and setters/getters; introduced setPathRewriterOnWSDLInterceptor() and generatePathRewriter() for path-aware WSDL rewriting; changed setPort() signature from String to int; removed excludeFromFlow annotation flag
SOAP Proxy Refactoring
core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java, core/src/main/java/com/predic8/membrane/core/proxies/AbstractProxy.java
Refactored SOAPProxy to use centralized WSDL utilities via new addAndGetWSDLInterceptor() helper; delegated port discovery to WSDLUtil; removed blocking flags from AbstractProxy
WSDL Publisher & Relocator
core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java, core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java
Updated message formatting and URL handling in WSDLPublisherInterceptor; made relocatingAttributes final; removed overloaded constructor and deprecated relocation() method in Relocator
Utility Updates
core/src/main/java/com/predic8/membrane/core/util/URLUtil.java, core/src/main/java/com/predic8/membrane/core/interceptor/InterceptorUtil.java, core/src/main/java/com/predic8/membrane/core/interceptor/RelocatingInterceptor.java
Renamed getName() to getNameComponent(); added moveToFirstPosition() utility; simplified content and GET checks in RelocatingInterceptor
Core Tests
core/src/test/java/com/predic8/membrane/core/interceptor/WSDLInterceptorTest.java, core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyTest.java, core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java, core/src/test/java/com/predic8/membrane/core/util/soap/WSDLUtilTest.java
Renamed test methods to remove test prefix; updated setPort() call to use int; added generatePathRewriter() and testGetNameComponent() tests; added WSDLUtilTest for path rewriting
SOAP Tutorial Tests
distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractSOAPTutorialTest.java, distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java, distribution/src/test/java/com/predic8/membrane/tutorials/soap/SOAPProxyTutorialTest.java, distribution/src/test/java/com/predic8/membrane/tutorials/soap/SampleSOAPServiceTutorialTest.java, distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java, distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLMessageValidationTutorialTest.yaml, distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractManualSOAPProxyTutorialTest.java, distribution/src/test/java/com/predic8/membrane/tutorials/soap/APIManualSOAPProxyTutorialTest.java, distribution/src/test/java/com/predic8/membrane/tutorials/soap/SoapProxyManualSOAPProxyTutorialTest.java
Added test hierarchy for SOAP tutorials with base classes and concrete test implementations covering WSDL retrieval, SOAP calls, web service explorer, and validation scenarios
SOAP Tutorial Configurations
distribution/tutorials/soap/10-Sample-SOAP-Service.yaml, distribution/tutorials/soap/20-SOAPProxy.yaml, distribution/tutorials/soap/30-WSDL-Rewriter.yaml, distribution/tutorials/soap/40-WSDL-Message-Validation.yaml, distribution/tutorials/soap/90-Manual-SOAPProxy.yaml
Added and updated YAML configurations for SOAP proxy tutorials with varying complexity levels and rewriting/validation features
Launcher Scripts
distribution/tutorials/soap/membrane.sh, distribution/tutorials/soap/membrane.cmd, core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java
Replaced Java version checks with directory-walk logic to auto-discover Membrane installation; added debug logging and explicit exit code in RouterCLI
Test & Data Files
core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java, core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java, distribution/tutorials/data/city.soap.xml, distribution/tutorials/data/invalid-city.soap.xml
Reduced visibility of test methods; added normalizeCRLF() utility; added SOAP request/response data files; removed invoke-sample-soap-service.sh script
Documentation
distribution/tutorials/soap/README.md, docs/ROADMAP.md
Updated README with new topics; added StreamTracing subsection to ROADMAP

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

7.x

Suggested reviewers

  • rrayst
  • christiangoerdes

Poem

🐰 Path rewriting hops along with grace,
WSDL endpoints find their rightful place,
Tutorials bloom with SOAP and flair,
The gateway guides with wisdom to spare!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main refactoring focus: streamlining WSDL handling, improving logging, and adjusting interceptor flow. It reflects the core changes across WSDLInterceptor, WSDLPublisherInterceptor, SOAPProxy, and related utilities.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@predic8 predic8 marked this pull request as draft January 8, 2026 12:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (1)

114-118: Update the comment to reflect the current interceptor insertion logic.

The comment states "add interceptors (in reverse order) to position 0", but addWSDLPublisherInterceptor() now uses addLast() at line 332, placing it at the end of the chain rather than position 0.

📝 Proposed comment update
-        // add interceptors (in reverse order) to position 0.
+        // add interceptors to configure WSDL handling
         addWebServiceExplorer();
         addWSDLPublisherInterceptor();
         addWSDLInterceptor();
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcdc7d4 and 477d87d.

📒 Files selected for processing (4)
  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/proxies/AbstractProxy.java
  • core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java
💤 Files with no reviewable changes (1)
  • core/src/main/java/com/predic8/membrane/core/proxies/AbstractProxy.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-22T10:09:12.663Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/interceptor/ws_addressing/WsaEndpointRewriter.java:47-81
Timestamp: 2025-08-22T10:09:12.663Z
Learning: In WS-A endpoint rewriter and similar HTTP processing components, avoid closing XMLEventReader/XMLEventWriter when they wrap HTTP streams from keep-alive sessions, as this can interfere with HTTP connection management. Only flush the writer to ensure output is written.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Automated tests
  • GitHub Check: Analyze (java)
🔇 Additional comments (5)
core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java (3)

32-32: LGTM! Static import improves readability.

Adding the static import for notFound makes line 222 more concise while maintaining clarity.


113-113: LGTM! Log message simplification is appropriate.

Removing the "WSDLPublisherInterceptor:" prefix is appropriate since the logger already includes the class name in its output format.


231-231: LGTM! Modern string formatting improves readability.

Using formatted() is more readable and idiomatic than string concatenation.

core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (1)

325-333: Verify that moving WSDLPublisherInterceptor to the end of the chain preserves WSDL serving functionality.

Changing from addFirst() to addLast() significantly alters the interceptor execution order. The WSDLPublisherInterceptor will now run after all other interceptors in the request flow, which may affect when and how WSDL documents are served to clients.

Combined with the change to WSDLInterceptor.excludeFromFlow (now false), this represents a coordinated flow restructuring. Ensure this doesn't break:

  • WSDL document retrieval via ?wsdl parameter
  • XSD document retrieval via ?xsd= parameter
  • Path rewriting in served WSDL documents
  • Integration with ValidatorInterceptor and other interceptors
#!/bin/bash
# Description: Find test files that verify WSDL serving functionality to ensure coverage

# Search for test files related to SOAP proxy and WSDL publisher
rg -l "WSDLPublisher|SOAPProxy" --type=java -g "*Test*.java"
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (1)

39-39: The XML content-type filtering in the parent class provides adequate safeguards; the flow participation change is safe.

WSDLInterceptor's parent class RelocatingInterceptor.handleResponse() enforces strict filtering that prevents processing non-XML responses (line 56-59 checks !exc.getResponse().isXML()). Additionally, Relocator only sets wsdlFound=true when WSDL SOAP namespace elements are detected. The interceptor execution order is intentional: WSDLInterceptor.addFirst() (line 277) runs early in the chain, while WSDLPublisherInterceptor.addLast() (line 332) runs at the end. The change is aligned with the WSDL handling refactor and existing test coverage validates the rewriting behavior.

…test

- Introduced `20-SOAPProxy.yaml` for configuring a SOAP proxy example.
- Added `SOAPProxyTutorialTest` and `AbstractSOAPTutorialTest` for integration testing.
@membrane-ci-server

Copy link
Copy Markdown

This pull request needs "/ok-to-test" from an authorized committer.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
@distribution/src/test/java/com/predic8/membrane/tutorials/soap/SOAPProxyTutorialTest.java:
- Line 1: Add the standard Apache License 2.0 copyright header used in this
package to the top of SOAPProxyTutorialTest.java; locate the file by the package
declaration "package com.predic8.membrane.tutorials.soap;" and the class
"SOAPProxyTutorialTest" and prepend the identical header block used in
AbstractSOAPTutorialTest.java so the file matches licensing/formatting across
the package.
🧹 Nitpick comments (1)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/SOAPProxyTutorialTest.java (1)

15-26: Consider renaming the test method to reflect its purpose.

The test method name adminConsole() doesn't clearly describe what it's testing. The test actually verifies WSDL retrieval from the SOAP proxy endpoint. A more descriptive name would improve readability and maintainability.

♻️ Suggested method name alternatives
     @Test
-    void adminConsole() {
+    void shouldReturnWsdlDefinitions() {
         // @formatter:off
         given()
         .when()

or

     @Test
-    void adminConsole() {
+    void testWsdlEndpointReturnsDefinitions() {
         // @formatter:off
         given()
         .when()
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 477d87d and 7ecedb3.

📒 Files selected for processing (3)
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractSOAPTutorialTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/SOAPProxyTutorialTest.java
  • distribution/tutorials/soap/20-SOAPProxy.yaml
✅ Files skipped from review due to trivial changes (1)
  • distribution/tutorials/soap/20-SOAPProxy.yaml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (1)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractSOAPTutorialTest.java (1)

1-26: LGTM!

Clean test base class implementation. The structure follows good testing patterns by providing a reusable base for SOAP tutorial tests.

- Introduced `30-WSDL-Rewriter.yaml` for demonstrating WSDL rewriting functionality.
- Added `WSDLRewriterTutorialTest` and expanded `AbstractCityServiceTest` for reusable SOAP test logic.
- Rewrote `membrane.sh` and added `membrane.cmd` for improved script execution and structure detection.
- Removed `invoke-sample-soap-service.sh` and integrated SOAP request example directly into YAML tutorials.
- Enhanced SOAP proxy examples in `20-SOAPProxy.yaml` and `10-Sample-SOAP-Service.yaml`.
- Updated `README.md` with new tutorial topics and streamlined documentation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
@core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java:
- Around line 203-205: The new setPort(int) in WSDLInterceptor breaks existing
tests that call setPort(String); add a backward-compatible overload public void
setPort(String port) in WSDLInterceptor that delegates to super.setPort(port) so
existing calls in WSDLInterceptorTest (e.g., setPort("") and setPort("2000"))
keep compiling, while retaining the new setPort(int) behavior.

In
@distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java:
- Around line 62-74: The test method webServiceExplorer sets a request body for
a GET which is unnecessary; remove the .body("Invalid") call from the
RestAssured given() chain in webServiceExplorer so the request is a plain GET
(keep the URL, .get("http://localhost:2000/my-service"), and the subsequent
assertions on statusCode, contentType(HTML), and body(containsString("Membrane
API Gateway: CityService"))).
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7ecedb3 and 7eb7420.

📒 Files selected for processing (14)
  • core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/SOAPProxyTutorialTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/SampleSOAPServiceTutorialTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java
  • distribution/tutorials/data/city-request.soap.xml
  • distribution/tutorials/soap/10-Sample-SOAP-Service.yaml
  • distribution/tutorials/soap/20-SOAPProxy.yaml
  • distribution/tutorials/soap/30-WSDL-Rewriter.yaml
  • distribution/tutorials/soap/README.md
  • distribution/tutorials/soap/invoke-sample-soap-service.sh
  • distribution/tutorials/soap/membrane.cmd
  • distribution/tutorials/soap/membrane.sh
💤 Files with no reviewable changes (1)
  • distribution/tutorials/soap/invoke-sample-soap-service.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/SOAPProxyTutorialTest.java
  • distribution/tutorials/soap/20-SOAPProxy.yaml
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-02T18:05:47.059Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 1947
File: distribution/tutorials/soap/membrane.sh:17-22
Timestamp: 2025-07-02T18:05:47.059Z
Learning: When using environment variable shortcuts like `$MEMBRANE_HOME` in shell scripts that look for installation directories, validate that required files (like `starter.jar` for Membrane) exist in the candidate directory before returning it. This prevents hard-to-diagnose runtime errors when the environment variable points to an invalid or stale location.

Applied to files:

  • distribution/tutorials/soap/membrane.sh
  • distribution/tutorials/soap/membrane.cmd
📚 Learning: 2025-11-23T15:59:51.742Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 2339
File: distribution/examples/web-services-soap/rest2soap-template/apis.yaml:17-32
Timestamp: 2025-11-23T15:59:51.742Z
Learning: In Membrane API Gateway YAML configuration files, response flows execute in reverse order. Steps that appear later in the response flow list actually execute first. For example, if a template references properties and setProperty steps appear after the template in the YAML, those setProperty steps will execute before the template renders.

Applied to files:

  • distribution/tutorials/soap/30-WSDL-Rewriter.yaml
📚 Learning: 2025-08-22T10:09:12.663Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/interceptor/ws_addressing/WsaEndpointRewriter.java:47-81
Timestamp: 2025-08-22T10:09:12.663Z
Learning: In WS-A endpoint rewriter and similar HTTP processing components, avoid closing XMLEventReader/XMLEventWriter when they wrap HTTP streams from keep-alive sessions, as this can interfere with HTTP connection management. Only flush the writer to ensure output is written.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
🧬 Code graph analysis (2)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java (1)
core/src/main/java/com/predic8/membrane/core/Constants.java (1)
  • Constants (24-103)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java (1)
core/src/main/java/com/predic8/membrane/core/Constants.java (1)
  • Constants (24-103)
🪛 Shellcheck (0.11.0)
distribution/tutorials/soap/membrane.sh

[warning] 8-8: Remove space after = if trying to assign a value (for empty string, use var='' ... ).

(SC1007)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (20)
core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java (1)

59-59: LGTM! Logging improvements enhance debuggability.

The additions improve observability and error messaging:

  • Startup args logging aids troubleshooting
  • Formatted error messages provide clearer feedback
  • Enhanced path resolution warnings include context

Also applies to: 253-253, 343-343

distribution/tutorials/soap/membrane.sh (2)

8-8: Shellcheck warning is a false positive.

The syntax CDPATH= cd is correct—it temporarily clears CDPATH for that command only to ensure reliable directory resolution. The space after = is intentional and necessary.


10-18: LGTM! Directory-walking launcher logic is sound.

The script correctly walks up the directory tree to locate the Membrane root and delegates to the main runner script. The validation of LICENSE.txt and scripts/run-membrane.sh provides a reasonable sanity check.

distribution/tutorials/soap/membrane.cmd (1)

9-20: LGTM! Windows launcher mirrors the shell script logic.

The directory-walking approach to locate Membrane root is consistent with membrane.sh, and the delegation to run-membrane.cmd maintains proper separation of concerns.

core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (1)

39-39: No duplicate execution risk from excludeFromFlow change.

The change from excludeFromFlow = true to false enables automatic flow participation. However, existing code in SOAPProxy.addWSDLInterceptor() already contains deduplication logic (getFirstInterceptorOfType(WSDLInterceptor.class).isEmpty()) that prevents duplicate instances even when both automatic inclusion and explicit configuration occur.

distribution/tutorials/data/city-request.soap.xml (1)

1-7: LGTM! Clean SOAP 1.1 request structure.

The SOAP envelope structure is correct with proper namespace declarations. The request targets the getCity operation with a hardcoded city name "Delhi", which aligns with the test expectations in AbstractCityServiceTest.java where the response population is asserted to be "34665600".

distribution/src/test/java/com/predic8/membrane/tutorials/soap/SampleSOAPServiceTutorialTest.java (1)

1-9: LGTM! Follows the tutorial test pattern correctly.

The test class correctly extends AbstractCityServiceTest and inherits the wsdl() and soapCall() test methods. The getTutorialYaml() override properly references the corresponding tutorial configuration file.

distribution/tutorials/soap/30-WSDL-Rewriter.yaml (2)

1-19: LGTM! Clear and helpful tutorial documentation.

The documentation clearly explains the use case for WSDL rewriting behind reverse proxies or load balancers, and provides actionable instructions for testing the configuration.


20-29: Configuration is correct and properly supports all parameters in flow.

The wsdlRewriter configuration with host, protocol, and port parameters is valid. All three parameters are properly exposed via @MCAttribute annotations in the WSDLInterceptor class, confirming they are supported in flow configuration. The setPort API correctly accepts an int parameter as expected.

distribution/tutorials/soap/10-Sample-SOAP-Service.yaml (2)

3-17: LGTM! Improved tutorial structure and clarity.

The restructured documentation is clearer with distinct Run, WSDL, and Invoke sections. The curl command correctly references the SOAP request file, and the endpoint URL is consistent with the configuration and tests.


19-24: LGTM! Configuration aligns with test expectations.

The API configuration with port 2000 and path /city-service matches what AbstractCityServiceTest expects. The sampleSoapService flow step is properly configured.

distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java (4)

1-12: LGTM! Proper imports and constant usage.

The imports are well-organized, using static imports for readability. Good use of the WSDL_SOAP11_NS constant from the Constants class.


13-13: LGTM! Appropriate abstract class declaration.

The class correctly extends AbstractSOAPTutorialTest, allowing concrete test classes to specify their tutorial YAML configurations.


32-42: Verify that Delhi is a supported city in the sample SOAP service.

The readFileFromBaseDir method is correctly available from DistributionExtractingTestcase through the parent class hierarchy, and the file ../data/city-request.soap.xml exists and loads correctly. However, the sample SOAP service documentation lists supported cities as: Bonn, Bielefeld, Manila, Da Nang, London, and New York—Delhi is not mentioned. Ensure Delhi is actually supported and returns population "34665600" before relying on this assertion.


15-30: The GPath expression is correct and matches the WSDL structure.

The definitions.service.port.address.@location expression correctly navigates the WSDL hierarchy. Rest-Assured's GPath automatically handles element namespace prefixes (ignoring them in path expressions), and the unprefixed location attribute is accessible directly via @location without namespace configuration. This expression is used identically in WSDLRewriterTutorialTest.java and aligns with the actual WSDL structure in city.wsdl, where the service has a single port with an address element containing the location attribute.

distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java (5)

1-25: LGTM: Imports are clean and well-organized.

The static imports from Constants and RestAssured improve test readability, and all imports are utilized in the test methods.


26-26: LGTM: Class declaration follows the tutorial test pattern.


33-47: LGTM: WSDL rewriting test is well-structured.

The test correctly validates:

  • WSDL accessibility
  • SOAP 1.1 namespace presence (using WSDL_SOAP11_NS constant)
  • URL rewriting from localhost to the public endpoint

The GPath expression for accessing the WSDL location attribute is appropriate.


28-31: Tutorial YAML file exists and is properly configured.

The method correctly returns the tutorial YAML filename. The file distribution/tutorials/soap/30-WSDL-Rewriter.yaml exists and contains proper WSDL rewriter configuration with host, protocol, and port overrides.


49-60: Test setup is correctly configured.

The SOAP request test data file city-request.soap.xml exists at distribution/tutorials/data/city-request.soap.xml, and the readFileFromBaseDir() method is available in the parent class DistributionExtractingTestcase. The test correctly validates SOAP call processing and response assertions.

predic8 added 11 commits January 8, 2026 21:32
- Removed unused `.body()` setups in `WSDLRewriterTutorialTest`.
- Simplified test method names in `WSDLInterceptorTest` for clarity and consistency.
- Introduced `40-WSDL-Message-Validation.yaml` for demonstrating WSDL validation in SOAP proxies.
- Added `invalid-city.soap.xml` as a sample invalid SOAP request payload for tutorial testing.
…ainst WSDL constraints

- Added a new test class extending `AbstractCityServiceTest` for validating WSDL message conformance with SOAP requests.
- Utilizes `40-WSDL-Message-Validation.yaml` and `invalid-city.soap.xml` for testing invalid scenarios.
…e`, and improve test coverage

- Introduced `getProxyEndpointName` for extracting endpoint names from proxy paths.
- Added `TestableSOAPProxy` and new test cases to validate WSDL path rewriting logic.
- Simplified `addWSDLInterceptor` and `setPathRewriter` methods for improved readability.
- Streamlined formatting and code consistency in `SOAPProxyTest`.
…ve test coverage

- Extracted WSDL-related logic into `WSDLUtil` and introduced new helper methods like `rewriteRelativeWsdlPath` for better modularity.
- Enhanced `SOAPProxy` initialization to streamline and centralize WSDL interceptor setup.
- Added `WSDLUtilTest` for unit testing path rewriting logic.
- Improved test coverage across WSDL-related test classes by adding and modifying cases in `SOAPProxyTest` and creating additional tests for `WSDLInterceptor`.
- Simplified and refactored existing methods to improve readability and maintainability.
…d, and improve test readability

- Removed redundant `hasContent` method from `RelocatingInterceptor`.
- Simplified `@MCElement` annotation in `WSDLInterceptor` by removing `excludeFromFlow` attribute.
- Improved readability and structure of assertions in `URLUtilTest`.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In
@core/src/main/java/com/predic8/membrane/core/interceptor/RelocatingInterceptor.java:
- Around line 46-49: RelocatingInterceptor currently calls
exc.getRequest().isGETRequest() without guarding against a null Request; update
the check in the method where this appears to first ensure exc.getRequest() !=
null before calling isGETRequest() (i.e., change the if to check
exc.getRequest() != null && !exc.getRequest().isGETRequest()), keep the same
debug log and return CONTINUE behavior when the condition matches, and ensure
the null-safe check follows the pattern used in
AdminRESTInterceptor/ReverseProxyingInterceptor/WebSocketExchangeWatcher/AdminApiInterceptor.

In
@core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java:
- Around line 226-228: WSDLInterceptor removed the setPort(String) API causing
test compilation failures; restore compatibility by adding a setPort(String)
overload in WSDLInterceptor that delegates to super.setPort(port) (e.g., public
void setPort(String port) { super.setPort(port); }) so existing callers in
WSDLInterceptorTest, ServiceProxyWSDLInterceptorsTest, and
SoapAndInternalProxyTest keep working without changing tests.

In @core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java:
- Around line 113-118: Fix the typo in the inline comment near the interceptor
setup: change "WebServiceExploroer" to "WebServiceExplorer" in the comment that
documents addWebServiceExplorer(), addWSDLPublisherInterceptor(),
addAndGetWSDLInterceptor(), and
setPathRewriterOnWSDLInterceptor(wsdlInterceptor) so the comment correctly reads
"Will be before WebServiceExplorer".

In @core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java:
- Around line 17-21: The regex and replacement in rewriteRelativeWsdlPath are
unsafe: change the Pattern relativePathPattern to anchor a literal dot (e.g.,
"^\\./[^/?]*\\?") so it only matches "./..." prefixes, and when building the
replacement use Matcher.quoteReplacement on replacementName (e.g., construct
"./" + Matcher.quoteReplacement(replacementName) + "?") before calling
relativePathPattern.matcher(path).replaceAll(...) so any '$' or '\' in
replacementName are treated literally.
🧹 Nitpick comments (10)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java (1)

17-17: Consider using explicit imports instead of wildcards.

While wildcard imports are functional, explicit imports improve code clarity and help avoid potential naming conflicts. However, this is a minor style preference and common in test code.

Example of explicit imports
-import org.junit.jupiter.api.*;
+import org.junit.jupiter.api.Test;

-import java.io.*;
+import java.io.IOException;

Also applies to: 19-19

core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyWSDLPublisherInterceptorTest.java (2)

20-20: Consider using a specific import instead of wildcard.

While wildcard static imports are functionally correct, using a specific import for getPathFromResource would make dependencies more explicit and avoid potential naming conflicts.

Suggested change
-import static com.predic8.membrane.test.TestUtil.*;
+import static com.predic8.membrane.test.TestUtil.getPathFromResource;

21-21: Consider pinning the Rest Assured version.

The library context indicates that Rest Assured's version is not specified in the pom.xml, which may lead to non-reproducible builds and potential compatibility issues as newer versions are released.

Based on learnings, ensure dependency versions are explicitly defined for build reproducibility.

core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyTest.java (1)

21-21: Consider avoiding wildcard import in tests if it risks ambiguity.

import com.predic8.membrane.core.util.*; can accidentally introduce type/staticmethod ambiguity; if it’s only needed for one symbol, a specific import is clearer.

core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java (1)

43-43: final map prevents reassignment, but external callers can still mutate it via getRelocatingAttributes().

If the intent is to reduce mutability/misuse, consider returning an unmodifiable view (or exposing explicit methods for allowed mutations).

Proposed adjustment (only if callers don’t rely on mutating the returned map)
 public Map<QName, String> getRelocatingAttributes() {
-    return relocatingAttributes;
+    return Collections.unmodifiableMap(relocatingAttributes);
 }

Also applies to: 125-127

core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java (1)

74-81: Nice coverage for getNameComponent(...) path variants.

Optional: consider adding "/" (and maybe "") expectations to pin root/empty-path behavior explicitly.

core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java (2)

31-38: getPort(List<Port>): consider null/empty handling (fail fast with a clearer message).

Right now ports == null will NPE; ports.isEmpty() falls through to the generic exception.

Possible tweak
 public static Port getPort(List<Port> ports) {
+    if (ports == null || ports.isEmpty())
+        throw new IllegalArgumentException("No ports provided in WSDL.");
     Port port = getPortByNamespace(ports, WSDL_SOAP11_NS);
     if (port == null)
         port = getPortByNamespace(ports, WSDL_SOAP12_NS);
     if (port != null)
         return port;
     throw new IllegalArgumentException("No SOAP/1.1 or SOAP/1.2 ports found in WSDL.");
 }

40-58: Port inspection loop is solid; logging could include port identity for faster debugging.

If getPortByNamespace hits malformed bindings, including something like port name / binding QName in the warn would make triage easier.

core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (1)

66-84: Consider including exception details in error log.

The error log on line 80 doesn't include the exception message, which could make debugging harder when URL parsing fails.

Suggested improvement
             } catch (URISyntaxException | MalformedURLException e) {
-                log.error("Cannot parse URL {}", path);
+                log.error("Cannot parse URL {}: {}", path, e.getMessage());
             }
core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (1)

253-268: Duplicate path rewriting logic with WSDLInterceptor.generatePathRewriter.

The lambda defined here is identical to the one in WSDLInterceptor.generatePathRewriter(String keypath) (lines 72-84 of WSDLInterceptor.java). Consider using the existing method to avoid duplication.

Proposed simplification
     private void setPathRewriterOnWSDLInterceptor(WSDLInterceptor wsdlInterceptor) {
         if (key.getPath() == null)
             return;
-        final String keyPath = key.getPath();
-        wsdlInterceptor.setPathRewriter(path -> {
-            try {
-                if (path.contains("://")) {
-                    return new URL(new URL(path), keyPath).toString();
-                }
-                return rewriteRelativeWsdlPath(path, URLUtil.getNameComponent(router.getConfiguration().getUriFactory(), keyPath));
-            } catch (URISyntaxException | MalformedURLException e) {
-                log.error("Cannot parse URL {}",path);
-            }
-            return path;
-        });
+        wsdlInterceptor.setPathRewriterOnWSDLInterceptor(key.getPath());
     }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1881d4f and c7041c1.

📒 Files selected for processing (16)
  • core/src/main/java/com/predic8/membrane/core/http/Request.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/RelocatingInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java
  • core/src/main/java/com/predic8/membrane/core/util/URLUtil.java
  • core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java
  • core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java
  • core/src/test/java/com/predic8/membrane/core/interceptor/WSDLInterceptorTest.java
  • core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyTest.java
  • core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyWSDLPublisherInterceptorTest.java
  • core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java
  • core/src/test/java/com/predic8/membrane/core/util/soap/WSDLUtilTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/SampleSOAPServiceTutorialTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLMessageValidationTutorialTest.java
✅ Files skipped from review due to trivial changes (2)
  • core/src/test/java/com/predic8/membrane/core/util/soap/WSDLUtilTest.java
  • core/src/main/java/com/predic8/membrane/core/http/Request.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLMessageValidationTutorialTest.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/server/WSDLPublisherInterceptor.java
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2026-01-07T12:43:52.805Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 2529
File: annot/src/main/java/com/predic8/membrane/annot/beanregistry/SpringContextAdapter.java:50-53
Timestamp: 2026-01-07T12:43:52.805Z
Learning: SpringContextAdapter in annot/src/main/java/com/predic8/membrane/annot/beanregistry/SpringContextAdapter.java is only used during tests, not in production code, so stub implementations throwing UnsupportedOperationException are acceptable.

Applied to files:

  • core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyTest.java
📚 Learning: 2025-09-19T11:12:26.787Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2156
File: core/src/main/java/com/predic8/membrane/core/openapi/validators/QueryParameterValidator.java:129-131
Timestamp: 2025-09-19T11:12:26.787Z
Learning: Request.get().path() in com.predic8.membrane.core.openapi.model.Request preserves the query string portion of the path, so URIFactory.createWithoutException(request.getPath()).getQuery() correctly extracts query parameters.

Applied to files:

  • core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyWSDLPublisherInterceptorTest.java
  • core/src/main/java/com/predic8/membrane/core/util/URLUtil.java
📚 Learning: 2025-08-22T10:09:12.663Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/interceptor/ws_addressing/WsaEndpointRewriter.java:47-81
Timestamp: 2025-08-22T10:09:12.663Z
Learning: In WS-A endpoint rewriter and similar HTTP processing components, avoid closing XMLEventReader/XMLEventWriter when they wrap HTTP streams from keep-alive sessions, as this can interfere with HTTP connection management. Only flush the writer to ensure output is written.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java
📚 Learning: 2025-09-10T06:50:06.396Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 2132
File: core/src/test/java/com/predic8/membrane/core/util/URITest.java:0-0
Timestamp: 2025-09-10T06:50:06.396Z
Learning: java.net.URI#getHost() returns IPv6 addresses WITH brackets included, not without brackets. For example, new URI("http://[2001:db8::1]:8080/foo").getHost() returns "[2001:db8::1]", not "2001:db8::1".

Applied to files:

  • core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java
📚 Learning: 2025-09-10T06:50:06.396Z
Learnt from: rrayst
Repo: membrane/api-gateway PR: 2132
File: core/src/test/java/com/predic8/membrane/core/util/URITest.java:0-0
Timestamp: 2025-09-10T06:50:06.396Z
Learning: java.net.URI#getHost() returns IPv6 addresses WITH brackets included, not without brackets. According to Java documentation, IPv6 addresses in URIs "must be enclosed in square brackets" and getHost() returns the host component with brackets for IPv6. For example, new URI("http://[2001:db8::1]:8080/foo").getHost() returns "[2001:db8::1]", not "2001:db8::1".

Applied to files:

  • core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java
🧬 Code graph analysis (5)
core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyTest.java (1)
core/src/test/java/com/predic8/membrane/core/openapi/util/OpenAPITestUtils.java (1)
  • OpenAPITestUtils (34-98)
core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyWSDLPublisherInterceptorTest.java (1)
core/src/test/java/com/predic8/membrane/test/TestUtil.java (1)
  • TestUtil (29-61)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java (1)
core/src/main/java/com/predic8/membrane/core/Constants.java (1)
  • Constants (24-103)
core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (2)
core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java (1)
  • WSDLUtil (13-59)
core/src/main/java/com/predic8/membrane/core/util/URLUtil.java (1)
  • URLUtil (19-55)
core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java (1)
core/src/main/java/com/predic8/membrane/core/util/URLUtil.java (1)
  • URLUtil (19-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (18)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/SampleSOAPServiceTutorialTest.java (1)

17-22: LGTM!

Clean test class that follows the established tutorial test pattern. The implementation correctly extends the base test class and configures the specific tutorial YAML file.

distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java (2)

29-44: Well-structured WSDL endpoint test.

The test properly validates the WSDL retrieval, content type, namespace presence, and importantly verifies that the service location is correctly rewritten to the proxy endpoint. The REST-assured pattern and XPath expression are appropriate for WSDL structure validation.


46-56: SOAP call test looks good.

The test correctly reads the SOAP request body from the filesystem and validates the response structure. The relative path usage with readFileFromBaseDir() should handle the file location properly based on the parent class infrastructure.

core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyWSDLPublisherInterceptorTest.java (1)

57-57: No action needed. The project requires Java 21 (configured in pom.xml and all CI/CD workflows), which fully supports the String.formatted() method introduced in Java 15. There is no compatibility issue.

Likely an incorrect or invalid review comment.

core/src/test/java/com/predic8/membrane/core/proxies/SOAPProxyTest.java (2)

96-103: RestAssured chain reformat looks good.

Readability improved; semantics unchanged.

Also applies to: 97-102


111-114: Expanded assertThrows lambda is clearer.

This formatting makes the failing operations obvious and keeps the assertion scoped correctly.

core/src/main/java/com/predic8/membrane/core/ws/relocator/Relocator.java (1)

57-72: getNewLocation(...) change is formatting-only.

No concerns from this diff.

core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java (1)

31-36: Assertion argument order fix is good.

Using assertEquals(expected, actual) improves failure messages.

core/src/main/java/com/predic8/membrane/core/util/URLUtil.java (1)

36-50: LGTM!

The method is well-documented and correctly handles the edge cases (no slash returns entire path, trailing slash returns empty string). The implementation is concise and aligns with the test coverage mentioned in the AI summary.

core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (1)

42-42: Verify the impact of removing excludeFromFlow = true.

The @MCElement annotation change now includes WSDLInterceptor in the interceptor flow. Confirm that this behavioral change is intentional and that existing configurations won't be affected.

core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (4)

21-39: LGTM!

Import changes align with the refactoring to use centralized WSDLUtil for port resolution and path rewriting.


89-95: LGTM!

Good use of pattern matching for instanceof, improving readability while maintaining the same functionality.


244-251: LGTM!

Clean implementation using Optional.orElseGet to lazily create and register the interceptor only when needed.


241-241: LGTM!

Good use of the centralized WSDLUtil.getPort to handle SOAP 1.1/1.2 port selection consistently.

core/src/test/java/com/predic8/membrane/core/interceptor/WSDLInterceptorTest.java (4)

41-53: LGTM!

Using DummyTestRouter provides proper router context needed for the interceptor initialization. The visibility change to package-private aligns with JUnit 5 conventions.


63-125: LGTM!

Test method renaming follows JUnit 5 conventions where the test prefix is no longer required. Method names remain descriptive.


102-108: LGTM!

Test correctly updated to use int parameter matching the new setPort(int) signature.


171-177: Verify intended behavior: query strings dropped for absolute URLs.

Line 175 shows that "http://api.predic8.de/service-b?WSDL" becomes "http://api.predic8.de/service-a" (query string dropped), while line 176 preserves the query for relative paths ("./service-b?WSDL""./service-a?WSDL"). This asymmetry is due to new URL(context, spec) behavior.

If WSDL location rewriting should preserve query strings for absolute URLs, the generatePathRewriter logic would need adjustment.

Comment thread core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java Outdated
Comment thread core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java Outdated
…terceptor setup

- Deleted the redundant `setPathRewriterOnWSDLInterceptor` method from `SOAPProxy`.
- Corrected a typo in method comments and variable usage (`WebServiceExploroer` -> `WebServiceExplorer`).
- Enhanced `setPathRewriter` call to streamline WSDL interceptor setup.
- Updated `URLUtilTest` to expand and clarify `getNameComponent` behavior.
- Refined `WSDLUtil` regex usage for better consistency.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java (3)

22-26: Redundant static import (URLUtil.* already covers getNameComponent).
The explicit import static ...URLUtil.getNameComponent; is unnecessary given import static ...URLUtil.*;.

Proposed diff
 import static com.predic8.membrane.core.util.URLParamUtil.DuplicateKeyOrInvalidFormStrategy.*;
 import static com.predic8.membrane.core.util.URLParamUtil.*;
 import static com.predic8.membrane.core.util.URLUtil.*;
-import static com.predic8.membrane.core.util.URLUtil.getNameComponent;
 import static org.junit.jupiter.api.Assertions.*;

30-38: Collapse repeated host() assertions into a small table/loop.
Same expected value across multiple inputs; a loop makes future edits less error-prone.

Proposed diff
 	@Test
 	void host() {
-		assertEquals("a", getHost("internal:a"));
-		assertEquals("a", getHost("internal://a"));
-		assertEquals("a", getHost("a"));
-		assertEquals("a", getHost("a/b"));
-		assertEquals("a", getHost("internal:a/b"));
-		assertEquals("a", getHost("internal://a/b"));
+		for (String in : new String[] {
+				"internal:a",
+				"internal://a",
+				"a",
+				"a/b",
+				"internal:a/b",
+				"internal://a/b"
+		}) {
+			assertEquals("a", getHost(in));
+		}
 	}

75-84: testGetNameComponent() coverage looks solid (empty, root, nested, trailing-slash).

Optional: reuse a single URIFactory instance
 	@Test
 	void testGetNameComponent() throws Exception {
-		assertEquals("", getNameComponent(new URIFactory(), ""));
-		assertEquals("", getNameComponent(new URIFactory(), "/"));
-		assertEquals("foo", getNameComponent(new URIFactory(), "foo"));
-		assertEquals("foo", getNameComponent(new URIFactory(), "/foo"));
-		assertEquals("bar", getNameComponent(new URIFactory(), "/foo/bar"));
-		assertEquals("bar", getNameComponent(new URIFactory(), "foo/bar"));
-		assertEquals("", getNameComponent(new URIFactory(), "foo/bar/"));
+		URIFactory uf = new URIFactory();
+		assertEquals("", getNameComponent(uf, ""));
+		assertEquals("", getNameComponent(uf, "/"));
+		assertEquals("foo", getNameComponent(uf, "foo"));
+		assertEquals("foo", getNameComponent(uf, "/foo"));
+		assertEquals("bar", getNameComponent(uf, "/foo/bar"));
+		assertEquals("bar", getNameComponent(uf, "foo/bar"));
+		assertEquals("", getNameComponent(uf, "foo/bar/"));
 	}
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (1)

29-29: Remove unused regex import.

The java.util.regex.* import appears to be unused in this file. The regex logic is contained within WSDLUtil.rewriteRelativeWsdlPath, which is statically imported and called, but Pattern or Matcher are not directly referenced here.

♻️ Proposed fix
-import java.util.regex.*;
core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (1)

21-21: Consider specific import over wildcard.

The import was changed from a specific ValidatorInterceptor import to a wildcard schemavalidation.* import. Unless multiple classes from this package are used, prefer specific imports for clarity.

♻️ Proposed fix
-import com.predic8.membrane.core.interceptor.schemavalidation.*;
+import com.predic8.membrane.core.interceptor.schemavalidation.ValidatorInterceptor;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7041c1 and 5047eb1.

📒 Files selected for processing (4)
  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java
  • core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java
  • core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-22T10:09:12.663Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/interceptor/ws_addressing/WsaEndpointRewriter.java:47-81
Timestamp: 2025-08-22T10:09:12.663Z
Learning: In WS-A endpoint rewriter and similar HTTP processing components, avoid closing XMLEventReader/XMLEventWriter when they wrap HTTP streams from keep-alive sessions, as this can interfere with HTTP connection management. Only flush the writer to ensure output is written.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
🧬 Code graph analysis (3)
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (2)
core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java (1)
  • WSDLUtil (14-62)
core/src/main/java/com/predic8/membrane/core/util/URLUtil.java (1)
  • URLUtil (19-55)
core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (1)
core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java (1)
  • WSDLUtil (14-62)
core/src/test/java/com/predic8/membrane/core/util/URLUtilTest.java (1)
core/src/main/java/com/predic8/membrane/core/util/URLUtil.java (1)
  • URLUtil (19-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (7)
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (2)

42-42: LGTM! Annotation change enables flow participation.

Removing excludeFromFlow = true allows the WSDLInterceptor to participate in the interceptor chain. This aligns with the PR objective to integrate the interceptor into the flow, and is consistent with the new path rewriting functionality and the RESPONSE_FLOW setting in the constructor.


66-84: URL rewriting logic is correct and thoroughly tested.

The generatePathRewriter() method at lines 72-84 correctly handles both absolute and relative path rewriting. The URL construction using new URL(new URL(path), keypath) properly rewrites URLs by replacing the path component while preserving protocol and host. This is validated by existing test coverage in WSDLInterceptorTest.generatePathRewriter():

  • Absolute URL: http://api.predic8.de/service-bhttp://api.predic8.de/service-a
  • Absolute URL with query params: http://api.predic8.de/service-b?WSDLhttp://api.predic8.de/service-a
  • Relative path: ./service-b?WSDL./service-a?WSDL

The keypath parameter from SOAPProxy.key.getPath() provides path values that work correctly with this logic.

Error handling at line 80 appropriately logs at ERROR level for URL parsing failures.

core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (5)

87-93: LGTM! Modernized loop structure.

The refactored loop uses pattern matching with instanceof, which is more concise and readable than the previous implementation. No functional changes.


111-116: LGTM! Clear interceptor initialization with helpful comments.

The refactored interceptor initialization clearly documents the reverse-order insertion behavior (using addFirst results in last-added being first in chain). The final execution order will be: WSDLInterceptor → WSDLPublisherInterceptor → WebServiceExplorer → (existing validator).

The addition of path rewriting configuration (line 116) integrates well with the new WSDLInterceptor capabilities.


239-239: LGTM! Centralized port selection logic.

Delegating to WSDLUtil.getPort(ports) eliminates code duplication and centralizes SOAP port selection logic. The utility method handles both SOAP 1.1 and 1.2 namespaces as the previous local implementation did.


242-249: LGTM! Well-structured lazy initialization.

The addAndGetWSDLInterceptor method elegantly handles both cases (existing or new interceptor) using Optional.orElseGet. This pattern ensures a single WSDLInterceptor instance exists and returns it for further configuration.


252-252: LGTM! Consistent use of type inference.

Using var for local variables where the type is obvious from the initializer (constructor call) reduces verbosity and improves readability. This is consistent with other var usage in the file.

Also applies to: 262-262

…ng, and improve test coverage

- Introduced `90-Manual-SOAPProxy.yaml` for setting up and testing manual SOAP proxies.
- Added `ManualSOAPProxyTutorialTest` to validate SOAP proxy setup and ensure WSDL compliance.
- Enhanced `moveToFirstPosition` utility for efficient WSDL interceptor addition and management.
- Updated multiple YAML tutorials and tests to align with new SOAP proxy configuration.
- Added `normalizeCRLF` utility in `StringTestUtil` for handling CRLF line endings in HTTP messages.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In
@core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java:
- Around line 225-227: WSDLInterceptor's setter changed signature to
setPort(int) which breaks callers passing Strings; add a backward-compatible
overload public void setPort(String port) in WSDLInterceptor that parses the
String and delegates to the int setter (e.g., parse with Integer.parseInt and
call the existing setPort(int)) so existing tests like SoapAndInternalProxyTest
and ServiceProxyWSDLInterceptorsTest continue to compile; keep the existing
setPort(int) implementation and ensure the new overload handles null/invalid
input consistently (e.g., throw NumberFormatException) to match previous
behavior.

In @core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java:
- Around line 113-118: The call to
wsdlInterceptor.setPathRewriterOnWSDLInterceptor(key.getPath()) silently skips
path rewriting when key.getPath() is null; update SOAPProxy (around the
wsdlInterceptor setup) to explicitly document this behavior and, to aid
debugging, perform a null check on key.getPath() and emit a debug/info log
stating that path rewriting is skipped when no path is configured (or leave a
clear inline comment if logging is undesired). Reference the SOAPProxy setup
block where addAndGetWSDLInterceptor() is called and the
wsdlInterceptor.setPathRewriterOnWSDLInterceptor(...) invocation, and mention
WSDLInterceptor's null-safe behavior in the comment or log message.

In @core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java:
- Around line 25-29: Update the JavaDoc on the StringTestUtil method that
normalizes test strings to CRLF so it accurately describes behavior: note that
the input parameter "s" may contain LF, CR, CRLF, or mixed line endings and the
method will normalize all of them to CRLF-terminated lines; keep the existing
@param and @return tags but change the description to reflect the broader
capability (accepts any line ending format and returns a CRLF-terminated HTTP
message).

In
@distribution/src/test/java/com/predic8/membrane/tutorials/soap/ManualSOAPProxyTutorialTest.java:
- Around line 32-45: In the soapCallInvalid test, replace the unconditional
.log().body() call with .log().ifValidationFails() to avoid noisy output, and
make the SOAP fault assertion more resilient by removing the fragile
body("Envelope.Body.Fault.faultstring", equalTo(...)) XPath check and instead
assert the response contains a fault indicator and the error token (e.g., assert
response body contains "faultstring" and still contains "INVALID"), keeping the
existing containsString("INVALID") check.
🧹 Nitpick comments (8)
core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java (1)

304-329: LGTM! Solid test coverage for chunked responses with charset.

The new nested test class correctly validates parsing of a chunked HTTP response with charset in the Content-Type header. The chunked encoding format is accurate (chunk size 0x17 = 23 bytes matches the body content), and the use of normalizeCRLF ensures proper CRLF line endings.

Optional: Consider a more descriptive class name

While "RealResponses" works, a more specific name like ChunkedResponseParsing or RealWorldChunkedResponses might better convey the test's focus. This is purely a readability nitpick and not essential.

core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java (1)

30-37: LGTM with optional suggestions.

The normalization logic is correct and handles all line ending variants (LF, CR, CRLF, and mixed) properly. The three-step approach is sound.

Optional improvements:

  1. Null handling: Consider adding a null check or documenting that null input is not supported.
🛡️ Optional null-safe implementation
     public static String normalizeCRLF(String s) {
+        if (s == null) {
+            return null;
+        }
         // First normalize all possible line endings to LF
         String lf = s.replace("\r\n", "\n")
                 .replace("\r", "\n");
  1. Test coverage: Since this is a utility method with non-trivial logic, consider adding unit tests to verify it correctly handles edge cases (empty strings, mixed line endings, consecutive line breaks, etc.).

Would you like me to generate test cases for this method?

core/src/main/java/com/predic8/membrane/core/interceptor/InterceptorUtil.java (1)

48-62: Consider edge case: null element in interceptors list.

Line 51 checks current != null, but the subsequent class equality check at line 51 assumes non-null. While the null check protects against NPE, if the list contains null elements, they will be silently skipped. Consider whether this is the intended behavior or if null elements should trigger an error.

core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (2)

65-83: Silent error recovery in path rewriting may mask issues.

The generatePathRewriter method catches URISyntaxException | MalformedURLException and logs an error, but then returns the original path. This silent recovery could mask configuration issues. Consider whether failing fast (throwing an exception) would be more appropriate during initialization, or at minimum, use a higher log level (warn/error).

Also, line 79 logs the error but the message format has both path and e.getMessage() - consider including the exception itself for full stack trace: log.error("Cannot parse URL {}", path, e);

📝 Improved error handling
         return path -> {
             try {
                 if (path.contains("://")) {
                     return new URL(new URL(path), keypath).toString();
                 }
                 return rewriteRelativeWsdlPath(path, URLUtil.getNameComponent(router.getConfiguration().getUriFactory(), keypath));
             } catch (URISyntaxException | MalformedURLException e) {
-                log.error("Cannot parse URL {} - {}", path,e.getMessage());
+                log.error("Cannot parse URL {}", path, e);
             }
             return path;
         };

71-83: Package-private method with unclear visibility intention.

The generatePathRewriter method is package-private but returns a public interface type (PathRewriter). This visibility seems intentional for testing, but consider adding a comment explaining why it's package-private or making it private if tests can work through the public API.

core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (2)

21-21: Avoid wildcard imports.

The change from importing ValidatorInterceptor specifically to using a wildcard import (com.predic8.membrane.core.interceptor.schemavalidation.*) reduces code clarity. Explicit imports make dependencies clearer and avoid potential naming conflicts.

♻️ Use explicit import
-import com.predic8.membrane.core.interceptor.schemavalidation.*;
+import com.predic8.membrane.core.interceptor.schemavalidation.ValidatorInterceptor;

113-118: Verify interceptor ordering comment accuracy.

The comment states interceptors are added "in reverse order" because they call addFirst, suggesting the final order is: WSDLInterceptor (first), WSDLPublisher, WebServiceExplorer, Validator (last). However, the comment also mentions "there might be already a validator interceptor that must go last."

If a validator already exists in the list when these are added, using addFirst will place all three new interceptors before the existing validator, which appears correct. But the phrasing "in reverse order" is slightly confusing—it might be clearer to state: "Added with addFirst to position them before any existing validator."

📝 Clarified comment
-        // Add interceptors (in reverse order) cause each one calls List.addFirst.
-        // This is needed because there might be already a validator interceptor that must go last
+        // Add interceptors using addFirst to position them before any existing validator.
+        // Final order: WSDLInterceptor, WSDLPublisher, WebServiceExplorer, [existing interceptors like Validator]
         addWebServiceExplorer(); // Will be last to validator
         addWSDLPublisherInterceptor(); // Will be before WebServiceExplorer
         var wsdlInterceptor = addAndGetWSDLInterceptor(); // WSDLInterceptor will be first
distribution/tutorials/soap/90-Manual-SOAPProxy.yaml (1)

6-17: Optional: dedupe repeated wsdlRewriter config to reduce drift.

The same wsdlRewriter { host, protocol, port } block appears twice; if YAML anchors are supported in this config format, using them would reduce copy/paste drift.

Also applies to: 21-32

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5047eb1 and 2921d8a.

📒 Files selected for processing (14)
  • core/src/main/java/com/predic8/membrane/core/interceptor/InterceptorUtil.java
  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
  • core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java
  • core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java
  • core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/ManualSOAPProxyTutorialTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java
  • distribution/tutorials/data/city.soap.xml
  • distribution/tutorials/soap/10-Sample-SOAP-Service.yaml
  • distribution/tutorials/soap/20-SOAPProxy.yaml
  • distribution/tutorials/soap/30-WSDL-Rewriter.yaml
  • distribution/tutorials/soap/40-WSDL-Message-Validation.yaml
  • distribution/tutorials/soap/90-Manual-SOAPProxy.yaml
✅ Files skipped from review due to trivial changes (1)
  • distribution/tutorials/data/city.soap.xml
🚧 Files skipped from review as they are similar to previous changes (3)
  • distribution/tutorials/soap/20-SOAPProxy.yaml
  • distribution/tutorials/soap/30-WSDL-Rewriter.yaml
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-22T10:09:12.663Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/interceptor/ws_addressing/WsaEndpointRewriter.java:47-81
Timestamp: 2025-08-22T10:09:12.663Z
Learning: In WS-A endpoint rewriter and similar HTTP processing components, avoid closing XMLEventReader/XMLEventWriter when they wrap HTTP streams from keep-alive sessions, as this can interfere with HTTP connection management. Only flush the writer to ensure output is written.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
🧬 Code graph analysis (4)
core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java (1)
core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java (1)
  • StringTestUtil (19-39)
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (2)
core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java (1)
  • WSDLUtil (14-62)
core/src/main/java/com/predic8/membrane/core/util/URLUtil.java (1)
  • URLUtil (19-55)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java (1)
core/src/main/java/com/predic8/membrane/core/Constants.java (1)
  • Constants (24-103)
core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (2)
core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java (1)
  • WSDLUtil (14-62)
core/src/main/java/com/predic8/membrane/core/interceptor/InterceptorUtil.java (1)
  • InterceptorUtil (19-73)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (13)
distribution/tutorials/soap/10-Sample-SOAP-Service.yaml (3)

1-5: LGTM: Documentation header simplified.

The title and description changes make the tutorial more concise and clearly state its purpose as a minimal SOAP endpoint for development and debugging.


7-12: LGTM: Startup instructions are clear.

The reformatted startup instructions maintain clarity while being more concise.


19-24: No changes needed. The sampleSoapService is a valid, documented Membrane component (SampleSoapServiceInterceptor), and the configuration is already clearly documented with usage instructions at the top of the file.

distribution/tutorials/soap/40-WSDL-Message-Validation.yaml (3)

17-18: Verify that the referenced data files exist at the specified paths.

The tutorial instructions reference ../data/city.soap.xml and ../data/invalid-city.soap.xml. Ensure these files exist relative to this YAML file's location.


20-24: Backend routing is correctly configured via WSDL.

The soapProxy automatically derives the backend service endpoint from the <soap:address location="..."/> element in the WSDL document. The configuration requires only the wsdl parameter; the target endpoint is extracted during initialization by parsing the WSDL's service definitions, ensuring proper request routing without explicit backend configuration.


22-22: The external WSDL at https://www.predic8.de/city-service?wsdl is the intended tutorial service. This pattern is consistent across all SOAP tutorials in the distribution, and the endpoint is stable and accessible. No changes are needed.

Likely an incorrect or invalid review comment.

core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java (2)

241-241: LGTM: Port selection centralized in WSDLUtil.

Delegating port selection to WSDLUtil.getPort(ports) improves code maintainability by centralizing the SOAP port discovery logic. The method handles both SOAP 1.1 and 1.2 namespaces and provides clear error messages.


244-246: LGTM: Clean use of moveToFirstPosition utility.

The addAndGetWSDLInterceptor() method effectively uses moveToFirstPosition to ensure the WSDLInterceptor is at the front of the chain, creating one if needed. The use of orElseThrow() is appropriate here since the supplier (WSDLInterceptor::new) will never return null.

core/src/main/java/com/predic8/membrane/core/interceptor/InterceptorUtil.java (1)

43-71: No action required. The project is configured for Java 21 (javac.source=21, javac.target=21), making the use of addFirst() fully compatible and appropriate.

core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (1)

41-41: Behavioral change: interceptor now configurable in standard flow.

Removing excludeFromFlow = true means WSDLInterceptor will now be configurable as part of the standard interceptor flow (instead of being reserved for utility purposes). This is a significant architectural change and should align with the new path rewriting functionality. Verify this change is intentional and document the implications in deployment guides if needed.

distribution/src/test/java/com/predic8/membrane/tutorials/soap/ManualSOAPProxyTutorialTest.java (1)

27-30: YAML selection override looks good.

distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractCityServiceTest.java (2)

29-44: WSDL rewrite assertion is clear and high-signal.


46-56: Set SOAP request Content-Type explicitly to avoid parsing/CI drift.

soapCall() posts XML without specifying a content-type; some stacks behave differently if it isn't text/xml; charset=utf-8 (SOAP 1.1) / application/soap+xml (SOAP 1.2).

Proposed change
@@
 import java.io.*;
 
 import static com.predic8.membrane.core.Constants.WSDL_SOAP11_NS;
+import static com.predic8.membrane.core.http.MimeType.TEXT_XML_UTF8;
 import static io.restassured.RestAssured.given;
 import static io.restassured.http.ContentType.XML;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
@@
     void soapCall() throws IOException {
         given()
             // File is read from FS use the same file as the user
             .body(readFileFromBaseDir("../data/city.soap.xml"))
+            .contentType(TEXT_XML_UTF8)
         .when()
             .post("http://localhost:2000/city-service")
         .then()
             .log().body()
             .body("Envelope.Body.getCityResponse.population", equalTo("34665600"));
     }

Comment thread core/src/main/java/com/predic8/membrane/core/proxies/SOAPProxy.java
Comment thread distribution/tutorials/soap/90-Manual-SOAPProxy.yaml
- Added `path` attribute to `WSDLInterceptor` for configurable WSDL rewrite paths.
- Improved error logging and exception handling in `WSDLInterceptor`.
- Updated `90-Manual-SOAPProxy.yaml` with refined tutorial structure and enhanced example configuration.
- Clarified `normalizeCRLF` utility documentation.
- Added new roadmap items for stream tracing improvements.
- Removed unnecessary `@Test` annotations from test methods.
- Streamlined method definitions and improved readability.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java:
- Around line 25-37: The normalizeCRLF method should validate its input and
ensure the returned message is CRLF-terminated: add a null check (e.g.,
Objects.requireNonNull(s, "s must not be null")) at the start of
StringTestUtil.normalizeCRLF and after normalizing line endings, ensure the
result ends with a trailing CRLF (append "\r\n" if it doesn't) so callers that
expect a CRLF-terminated HTTP message always get one; update the Javadoc to
state the parameter is non-null and that the return value is guaranteed to end
with CRLF.
🧹 Nitpick comments (4)
core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java (1)

21-23: Make inputStreamFrom charset explicit to avoid platform-dependent tests.

string.getBytes() uses the platform default charset, which can make tests flaky across environments. Consider StandardCharsets.UTF_8 (or the charset you want to model for HTTP bytes).

Proposed change
 import java.io.*;
+import java.nio.charset.StandardCharsets;
 ...
     public static InputStream inputStreamFrom(String string) {
-        return new ByteArrayInputStream(string.getBytes());
+        return new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8));
     }
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (2)

233-235: Type safety improvement with potential breaking change.

Changing the parameter type from String to int improves type safety. Since this is annotated with @MCAttribute, it's primarily used by the configuration framework, which should handle the conversion correctly. However, if any code directly calls this method with a String, it will break at compile time.


237-251: LGTM: Standard getter/setter with good documentation.

The path accessor methods are well-implemented. The javadoc on setPath clearly explains the SOAPProxy integration context.

📝 Optional: Add @return javadoc to getPath for completeness
     public String getPath() {
+        /** @return The configured path for service location rewriting */
         return path;
     }
distribution/tutorials/soap/90-Manual-SOAPProxy.yaml (1)

22-22: Clarify the comment about interceptor ordering.

The comment states "The wsdlRewriter must be the first of the following interceptors," but there's a rewriter interceptor before it on line 23. Consider rephrasing to "The wsdlRewriter must be the first WSDL-related interceptor" or "The wsdlRewriter must come before wsdlPublisher, webServiceExplorer, and validator" to avoid confusion.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2921d8a and 1689c03.

📒 Files selected for processing (5)
  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
  • core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java
  • core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java
  • distribution/tutorials/soap/90-Manual-SOAPProxy.yaml
  • docs/ROADMAP.md
✅ Files skipped from review due to trivial changes (1)
  • docs/ROADMAP.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-22T10:09:12.663Z
Learnt from: predic8
Repo: membrane/api-gateway PR: 2068
File: core/src/main/java/com/predic8/membrane/core/interceptor/ws_addressing/WsaEndpointRewriter.java:47-81
Timestamp: 2025-08-22T10:09:12.663Z
Learning: In WS-A endpoint rewriter and similar HTTP processing components, avoid closing XMLEventReader/XMLEventWriter when they wrap HTTP streams from keep-alive sessions, as this can interfere with HTTP connection management. Only flush the writer to ensure output is written.

Applied to files:

  • core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java
🧬 Code graph analysis (1)
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (2)
core/src/main/java/com/predic8/membrane/core/util/soap/WSDLUtil.java (1)
  • WSDLUtil (14-62)
core/src/main/java/com/predic8/membrane/core/util/URLUtil.java (1)
  • URLUtil (19-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (7)
core/src/main/java/com/predic8/membrane/core/interceptor/WSDLInterceptor.java (6)

21-21: LGTM: Imports support new path rewriting functionality.

The new imports enable the path rewriting capabilities added in this PR.

Also applies to: 34-34


41-41: LGTM: Annotation change aligns with PR objectives.

Removing excludeFromFlow = true enables this interceptor to participate in the normal processing flow, as intended.


54-57: LGTM: Field addition is well-documented.

The new path field is properly documented and follows standard patterns.


68-71: LGTM: Initialization logic is correctly placed.

The conditional initialization in init() ensures path rewriting is only configured when needed.


73-77: LGTM: Delegation method with proper null handling.

The method correctly guards against null input and delegates to the path rewriter generator.


79-91: Remove the URL manipulation concern; verify exception handling design intent.

The test at WSDLInterceptorTest.java:172-177 confirms the URL combination logic on lines 82-83 is correct. The test verifies that new URL(new URL("http://api.predic8.de/service-b"), "service-a") correctly produces "http://api.predic8.de/service-a", which shows that keypath properly replaces the last path component when the input is an absolute URL.

Regarding exception handling on line 88: The method wraps checked exceptions in RuntimeException after logging the error. This is a fail-fast design choice appropriate for WSDL URL rewriting, where invalid URLs should not be silently ignored. However, no error case tests exist to verify whether this is the intended behavior for production scenarios or if error recovery would be beneficial.

distribution/tutorials/soap/90-Manual-SOAPProxy.yaml (1)

50-56: Clarify that custom flow does not fully override auto-addition of interceptors in soapProxy.

The tutorial comments (lines 5-9) suggest that providing a custom flow allows precise control over interceptors, but this is misleading. The soapProxy automatically adds interceptors even when a custom flow is provided:

  • wsdlRewriter (WSDLInterceptor): Deduplicated—if present in custom flow, it's moved to the first position; otherwise a new one is created
  • wsdlPublisher (WSDLPublisherInterceptor): Added only if not already in custom flow
  • webServiceExplorer (WebServiceExplorerInterceptor): Always added, creating a new instance even if one exists in custom flow

For the custom flow shown here (lines 50-56), the resulting interceptor chain will be: wsdlRewriter, wsdlPublisher, webServiceExplorer, then validator—not just the two interceptors defined in the flow.

To achieve precise control over the interceptor chain, the tutorial recommends (line 12-13) using an api instead of soapProxy, as demonstrated in the earlier example. Consider adding a clarifying comment or updating the explanation to make this behavior explicit.

- Updated `StringTestUtil` to ensure consistent UTF-8 encoding in `inputStreamFrom`.
- Refactored `WSDLRewriterTutorialTest` and related test URLs to dynamically use ports via `getPort()`.
- Introduced two new test classes (`APIManualSOAPProxyTutorialTest` and `SoapProxyManualSOAPProxyTutorialTest`) for enhanced modularity and clarity.
- Converted `ManualSOAPProxyTutorialTest` into an abstract class for better reusability.
- Removed redundant `getPort` method from `APIManualSOAPProxyTutorialTest` by using defaults from superclass.
- Reordered assertion parameters in `ResponseTest` for consistency.
@predic8 predic8 marked this pull request as ready for review January 12, 2026 07:33
@predic8 predic8 requested a review from rrayst January 12, 2026 07:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractManualSOAPProxyTutorialTest.java (1)

32-46: Minor formatting inconsistency on line 44.

There's an extra space before the closing parenthesis: .body(containsString("INVALID") );

Suggested fix
-            .body(containsString("INVALID") );
+            .body(containsString("INVALID"));
core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java (1)

78-83: Naming inconsistency: parseStartLine1 vs testParseStartLine2/testParseStartLine3

This method was renamed to parseStartLine1, but the other two related methods retain the test prefix (testParseStartLine2, testParseStartLine3). Consider using consistent naming across these related test methods.

♻️ Suggested fix for consistent naming

Either keep the test prefix:

 @Test
-void parseStartLine1() throws IOException {
+void testParseStartLine1() throws IOException {

Or remove it from all three:

 @Test
-void testParseStartLine2() throws IOException {
+void parseStartLine2() throws IOException {
...
 @Test
-void testParseStartLine3() throws IOException {
+void parseStartLine3() throws IOException {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1689c03 and 0c3e7ba.

📒 Files selected for processing (6)
  • core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java
  • core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/APIManualSOAPProxyTutorialTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractManualSOAPProxyTutorialTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/SoapProxyManualSOAPProxyTutorialTest.java
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • distribution/src/test/java/com/predic8/membrane/tutorials/soap/WSDLRewriterTutorialTest.java
🧰 Additional context used
🧬 Code graph analysis (2)
distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractManualSOAPProxyTutorialTest.java (1)
core/src/main/java/com/predic8/membrane/core/http/MimeType.java (1)
  • MimeType (31-214)
core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java (1)
core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java (1)
  • StringTestUtil (22-42)
🔇 Additional comments (8)
core/src/test/java/com/predic8/membrane/core/util/StringTestUtil.java (2)

18-20: LGTM! Explicit UTF-8 encoding is a good improvement.

Using UTF_8 explicitly instead of the platform default charset ensures consistent behavior across different environments and prevents subtle encoding bugs in tests.

Also applies to: 24-26


28-40: LGTM! Clean and correct line-ending normalization.

The two-step approach (normalize to LF first, then convert to CRLF) correctly handles all line ending variants including mixed endings. The Javadoc clearly explains the purpose for HTTP message testing.

distribution/src/test/java/com/predic8/membrane/tutorials/soap/AbstractManualSOAPProxyTutorialTest.java (1)

25-30: LGTM!

Good use of template method pattern with the abstract class. The getTutorialYaml() override allows concrete subclasses to reuse the test logic while specifying different configurations.

distribution/src/test/java/com/predic8/membrane/tutorials/soap/APIManualSOAPProxyTutorialTest.java (1)

17-21: LGTM!

Simple concrete test class that inherits all behavior from the abstract parent. The JavaDoc clearly documents the port configuration.

distribution/src/test/java/com/predic8/membrane/tutorials/soap/SoapProxyManualSOAPProxyTutorialTest.java (1)

17-23: LGTM!

Clean implementation that overrides only what's needed. Per the AI summary, port 2001 aligns with the YAML configuration in 90-Manual-SOAPProxy.yaml.

core/src/test/java/com/predic8/membrane/core/http/ResponseTest.java (3)

78-203: Good practice: Package-private visibility for JUnit 5 tests.

The visibility changes from public to package-private for all test methods align with JUnit 5 best practices, which no longer require test methods to be public.

Note: The AI summary incorrectly states that @Test annotations were stripped. All @Test annotations remain intact (visible on lines 78, 85, 92, 99, 110, 127, 139, 158, 168, 189, 195, 200), and these tests will continue to execute normally.


185-186: LGTM: Correct assertion parameter order.

The assertion now correctly places the expected value (0) before the actual value (res3.getBody().getContent().length), following JUnit conventions.


299-325: Well-structured test for chunked response with charset handling.

The new RealResponses nested class with the chunkedCharset test is well-implemented:

  • Uses StringTestUtil.normalizeCRLF to properly handle line endings for HTTP message parsing
  • Tests a realistic 404 chunked response with charset=us-ascii
  • Validates status code, content-type header, and decoded body content

One minor consideration: the test data includes a set-cookie header with a date in January 2026. This is fine for test purposes but consider using a more generic/past date if this might cause confusion during code archaeology.

@predic8 predic8 merged commit 50c4e25 into master Jan 12, 2026
1 of 3 checks passed
@predic8 predic8 deleted the soapproxy-wsdlinterceptor-yaml-fix branch January 12, 2026 12:29
This was referenced Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants