/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.services.soap.api.message.dispatcher;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toMap;
import static org.mule.service.http.api.HttpConstants.Method.POST;
import static org.mule.service.http.api.HttpHeaders.Names.CONTENT_TYPE;
import org.mule.runtime.api.lifecycle.InitialisationException;
import org.mule.runtime.extension.api.soap.message.DispatchingRequest;
import org.mule.runtime.extension.api.soap.message.DispatchingResponse;
import org.mule.runtime.extension.api.soap.message.MessageDispatcher;
import org.mule.service.http.api.HttpService;
import org.mule.service.http.api.client.HttpClient;
import org.mule.service.http.api.client.HttpClientConfiguration;
import org.mule.service.http.api.domain.ParameterMap;
import org.mule.service.http.api.domain.entity.InputStreamHttpEntity;
import org.mule.service.http.api.domain.message.request.HttpRequest;
import org.mule.service.http.api.domain.message.response.HttpResponse;
import org.mule.services.soap.api.exception.DispatchingException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.TimeoutException;
/**
* Default {@link MessageDispatcher} implementation that aims to dispatch messages through HTTP
* with a prebuilt default configuration.
*
* @since 4.0
*/
public final class DefaultHttpMessageDispatcher implements MessageDispatcher {
private final HttpClient client;
public DefaultHttpMessageDispatcher(HttpService service) {
this.client = service.getClientFactory().create(new HttpClientConfiguration.Builder()
.setName("wsc-http-dispatcher")
.build());
}
@Override
public void initialise() throws InitialisationException {
client.start();
}
/**
* {@inheritDoc}
* <p>
* Dispatches a Soap message through http adding the SoapAction header, if required, and the content-type.
*/
@Override
public DispatchingResponse dispatch(DispatchingRequest context) {
ParameterMap parameters = new ParameterMap();
context.getHeaders().forEach(parameters::put);
// It's important that content type is bundled with the headers
parameters.put(CONTENT_TYPE, context.getContentType());
HttpRequest request = HttpRequest.builder()
.setUri(context.getAddress())
.setMethod(POST)
.setEntity(new InputStreamHttpEntity(context.getContent()))
.setHeaders(parameters)
.build();
try {
HttpResponse response = client.send(request, 5000, false, null);
InputStream content = ((InputStreamHttpEntity) response.getEntity()).getInputStream();
return new DispatchingResponse(content, response.getHeaderValueIgnoreCase(CONTENT_TYPE), toHeadersMap(response));
} catch (IOException e) {
throw new DispatchingException("An error occurred while sending the SOAP request");
} catch (TimeoutException e) {
throw new DispatchingException("The SOAP request timed out", e);
}
}
/**
* Collects all the headers returned by the http call.
*/
private Map<String, String> toHeadersMap(HttpResponse response) {
return response.getHeaderNames().stream()
.collect(toMap(identity(), name -> response.getHeaderValues(name).stream().collect(joining(" "))));
}
/**
* {@inheritDoc}
*/
@Override
public void dispose() {
client.stop();
}
}