Call POX web service from Spring Integration - spring-integration

I'm using Spring Integration in a project that integrates (successfully) various ReST/JSON and SOAP endpoints.
Now I need to call a BusinessWorks instance that is configured to accept Plain-Old-Xml-over-HTTP.
From the "Spring Integration in Action book", I got a hint that I should use int-ws:outbound-gateway for this.
This configuration generates the correct request, but in SOAP:
<int-ws:outbound-gateway
uri="..."
request-channel="request" reply-channel="reply"
marshaller="marshaller" unmarshaller="unmarshaller"/>
I can't figure out how to configure this to send the object in the payload as POX (no SOAP envelope).
I tried this:
<int-ws:outbound-gateway
uri="..."
request-channel="request" reply-channel="reply"
marshaller="marshaller" unmarshaller="unmarshaller"
message-factory="poxMessageFactory"/>
<bean id="poxMessageFactory"
class="org.springframework.ws.pox.dom.DomPoxMessageFactory"/>
The request seems to switch correctly to XML only but the body of the request is empty (no trace of the object present in the Spring Integration payload).
Can someone tell me what I am doing wrong or how to achieve what I am trying to do?

I think this is an omission in the AbstractWebServiceOutboundGateway:
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
Object payload = this.requestMessage.getPayload();
if (message instanceof SoapMessage) {
this.doWithMessageInternal(message, payload);
AbstractWebServiceOutboundGateway.this.headerMapper
.fromHeadersToRequest(this.requestMessage.getHeaders(), (SoapMessage) message);
if (this.requestCallback != null) {
this.requestCallback.doWithMessage(message);
}
}
}
Pay attention to the if (message instanceof SoapMessage) {.
So, indeed we miss there the fact that message can be different type.
Please, open JIRA bug on the matter.
Meanwhile as a workaround I would suggest you to use WebServiceTemplate directly instead of <int-ws:outbound-gateway> you can call it from the <service-activator> using marshalSendAndReceive() method for interaction.

Related

Spring Integration WebFlux outboundGateway ClientHttpResponse to Mono<Object>

How do we convert the Flux<DataBuffer> of ClientHttpResponse to Mono<SomeDto>. Also, can we get access to MessageHeaders in the bodyExtractor. Please suggest.
.handle(WebFlux.outboundGateway(apiUrl, webClient)
.httpMethod(POST)
.mappedRequestHeaders(CONTENT_TYPE)
.bodyExtractor((clientHttpResponse, context) -> validateAPIResponse(clientHttpResponse)))
private Mono<Object> validateAPIResponse(final ClientHttpResponse clientHttpResponse) {
var httpStatus = clientHttpResponse.getStatusCode();
// check for 500
if (httpStatus.is5xxServerError())
throw new SomeException(.......);
var responseMono = new Jackson2JsonDecoder().decodeToMono(clientHttpResponse.getBody(), ResolvableType.forClass(SomDto.class), null,
null);
// check for any other than 200
if (!httpStatus.is2xxSuccessful())
return responseMono.map(response -> {
throw new SomeOtherException(response.getSomeField(), httpStatus);
});
You can just delegate to BodyExtractors.toFlux(SomDto.class). I'm not sure if you really need a custom BodyExtractor, if just expectedResponseType(SomDto.class) should be enough for you produce such a Mono. Not sure also if you need to handle those errors yourself: the framework does a decent job on the matter.
Yes, you cannot get access to MessageHeaders in this BodyExtractor context since it has nothing to do with messaging.
You can get access to those headers a bit downstream when you already got a reply from this WebFlux gateway. If your reply is really very tied to headers, then you need to look into producing a generic reply (like that Flux<DataBuffer>) and then convert it appropriately downstream in a transformer where you already get access to the whole request message and its headers.
See also this in docs:
Spring Integration provides ClientHttpResponseBodyExtractor as a identity function to produce (downstream) the whole ClientHttpResponse and any other possible custom logic.

How to setup ContentType for Azure ServiceBus from Spring JMS

I'm trying to use library azure-servicebus-jms-spring-boot-starter to send messages to topic. Everything works, however messages are being stored in subscriptions as application/xml type and I can't find the way how to setup this correctly to have them stored as application/json.
I've tried to configure message converter to send ContentType as described here but that doesn't work either.
#Bean
public MessageConverter jacksonJmsMessageConverter() {
final MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(){
#Override
protected TextMessage mapToTextMessage(Object object, Session session, ObjectWriter objectWriter)
throws JMSException, IOException {
final TextMessage message = super.mapToTextMessage(object, session, objectWriter);
message.setStringProperty("ContentType", "application/json");
return message;
}
};
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
converter.setObjectMapper(objectMapper);
return converter;
}
There is no exposed means of setting the content-type on the messages sent from the Qpid JMS client. The client itself uses this field as part of the JMS mapping to AMQP to distinguish certain message types that it sends and to determine at receive time what certain messages should be presented as.
It is technically possible to use reflection to reach in and so the value but the APIs you have to use from the JmsMessageFacade class are not public and could change with any release so choosing to do so comes with significant risk.

ServiceStack Message via RabbitMq routing to verb other than POST

implementing service bus with servicestack and rabbitmq here.
Documentation states "each message will instead be executed by the best matching ServiceStack Service that handles the message with either a Post or Any fallback verb".
How then would I make the published message from the client route to PUT?
Thanks in advance for any suggestions or samples.
each message will instead be executed by the best matching ServiceStack Service that handles the message with either a Post or Any fallback verb"
This documentation says that messages are treated as POST requests, as such can only be handled with Post(Request) or Any(Request) handlers. This is the same as ServiceStack's SOAP Support where all SOAP request are POST's, which you can ensure is accessible by SOAP/MQ requests by maintaining separate Request DTO's (a common and recommended practice) and implementing them using Any() so they're still accessible by both PUT and POST requests, e.g:
[Route("/customers", "POST"]
public class CreateCustomer { ... }
[Route("/customers/{Id}", "PUT"]
public class UpdateCustomer { ... }
public class CustomerService : Service
{
public object Any(CreateCustomer request) { ... }
public object Any(UpdateCustomer request) { ... }
}
This service enables access to the service via POST /customers and PUT /customers/1 HTTP routes while still allowing them to be accessed via SOAP/MQ.

ServiceStack.Razor CustomHttpHandler not displaying for HttpStatusCode.BadRequest

I'm trying to get a minimal app working using ServiceStack.Razor, and I'm having trouble getting a CustomHttpHandler to work. I've followed the instructions here and here, but it's not working right.
I'm using the following code to register a custom http handler for HttpStatusCode.BadRequest:
public override void Configure(Container container)
{
this.Plugins.Add(new RazorFormat());
this.SetConfig(new EndpointHostConfig
{
CustomHttpHandlers =
{
{ HttpStatusCode.NotFound, new RazorHandler("/notfound") },
{ HttpStatusCode.BadRequest, new RazorHandler("/error") }
},
DebugMode = true
});
}
The thing is, the /notfound handler works perfectly for 404s, but no matter what I do, I can't get the /error razor file to display whenever an ArgumentNullException is thrown.
My service method looks like this:
public object Any(Hello request)
{
if (string.IsNullOrEmpty(request.Name))
{
throw new ArgumentNullException("Name");
}
return new HelloResponse { Result = "Hello " + request.Name };
}
ServiceStack returns a 400 status, which is fine, but it still displays the view I have for HelloResponse:
What am I missing? Am I misunderstanding how CustomHttpHandlers are supposed to work?
For reference, I put the project up on github.
Yeah the CustomHttpHandlers are just meant for handling un-handled system generated errors. Currently they're limited to:
NotFound (404) for un-handled requests
Forbidden (403) when a request is made to an forbidden file or resource
These are the errors happen outside of ServiceStack and so isn't able to be handled by existing ServiceStack's event hooks or user-defined custom logic, so we allow users to modify the behavior in this case via CustomHttpHandlers.
The Error Handling wiki describes how to handle errors in ServiceStack.
Though it might make sense (since it's opt-in) to allow a fallback after the exception is handled to allow it to be further handled by rendering it to a user-specified page, that you're expecting to do here.
We'll look at trying to explore something like this in the future. Feel free to add future feature requests like these to ServiceStack's issue list so we don't forget.

Logging Servicestack Bad Requests

Is there a way to log the validation results which get populated in the ResponseStatus when you have the ValidationFeature plugin enabled?
From what i can understand, any requests coming in get validated and if the validation passes then it goes to the service. Using request filters i can log the requests coming in however using the response filters i can only log valid requests.
I trying to log all responses especially HttpStatus 400 (Bad request) which is returned as a result of a validation error.
I have also tried to play a bit with the RequestLog plugin but from what i understood what gets logged are only valid request (i.e requests that went to the service).
I hope you understand what i am trying to say.
Look to see how 7digital have customized ServiceStack's Validation Feature to support logging.
Related Features
The new API supports the concept of a ServiceRunner you can override to add your own event and exception hooks you can read about in the wiki.
There is also the built-in Request Logger that lets you expect details of the more recently processed requests.
Create an issue on the GitHub project if you want to see logging in the validation feature.
A quick way to log errors from the ValidationFeature plugin is simply thus:
public override void Configure(Container container)
{
...etc...
Plugins.Add(new RequestLogsFeature() { etc });
Plugins.Add(new ValidationFeature()
{
ErrorResponseFilter = MyValidationError
});
...etc...
}
public object MyValidationError(ValidationResult validationResult, object errorDto)
{
Container.Resolve<IRequestLogger>().Log(null, null, errorDto, TimeSpan.Zero);
return errorDto;
}
However, in my case, I realized that logging validation errors in the service itself is not the proper place; I instead log these errors in the applications that consume the service.

Resources