/*
* Copyright (c) 2009, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.synapse.transport.passthru;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axiom.util.blob.OverflowBlob;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.AddressingConstants;
import org.apache.axis2.addressing.AddressingHelper;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.TransportOutDescription;
import org.apache.axis2.handlers.AbstractHandler;
import org.apache.axis2.transport.MessageFormatter;
import org.apache.axis2.transport.OutTransportInfo;
import org.apache.axis2.transport.TransportSender;
import org.apache.axis2.transport.base.BaseConstants;
import org.apache.axis2.transport.base.threads.NativeThreadFactory;
import org.apache.axis2.transport.base.threads.WorkerPool;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpException;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.nio.NHttpServerConnection;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.nio.reactor.IOReactorExceptionHandler;
import org.apache.http.protocol.HTTP;
import org.apache.synapse.transport.http.conn.ClientConnFactory;
import org.apache.synapse.transport.http.conn.ProxyConfig;
import org.apache.synapse.transport.http.conn.Scheme;
import org.apache.synapse.transport.nhttp.NhttpConstants;
import org.apache.synapse.transport.nhttp.config.ClientConnFactoryBuilder;
import org.apache.synapse.transport.nhttp.config.ProxyConfigBuilder;
import org.apache.synapse.transport.nhttp.util.MessageFormatterDecoratorFactory;
import org.apache.synapse.transport.nhttp.util.NhttpUtil;
import org.apache.synapse.transport.passthru.config.SourceConfiguration;
import org.apache.synapse.transport.passthru.config.TargetConfiguration;
import org.apache.synapse.transport.passthru.connections.TargetConnections;
import org.apache.synapse.transport.passthru.core.PassThroughSenderManager;
import org.apache.synapse.transport.passthru.jmx.MBeanRegistrar;
import org.apache.synapse.transport.passthru.jmx.PassThroughTransportMetricsCollector;
import org.apache.synapse.transport.passthru.jmx.TransportView;
import org.apache.synapse.transport.passthru.util.PassThroughTransportUtils;
import org.apache.synapse.transport.passthru.util.RelayUtils;
import org.apache.synapse.transport.passthru.util.SourceResponseFactory;
import org.wso2.caching.CachingConstants;
import org.wso2.caching.digest.DigestGenerator;
import javax.xml.stream.XMLStreamException;
import java.io.IOException;
import java.io.OutputStream;
import java.rmi.RemoteException;
import java.util.Locale;
import java.util.Map;
/**
* PassThroughHttpSender for Synapse based on HttpCore and NIO extensions
*/
public class PassThroughHttpSender extends AbstractHandler implements TransportSender {
protected Log log;
/** IOReactor used to create connections and manage them */
private DefaultConnectingIOReactor ioReactor;
/** Protocol handler */
private TargetHandler handler;
/** I/O dispatcher */
private ClientIODispatch ioEventDispatch;
/** The connection factory */
private ClientConnFactory connFactory;
/** Delivery agent used for delivering the messages to the servers */
private DeliveryAgent deliveryAgent;
/** The protocol scheme of the sender */
private Scheme scheme;
/** The configuration of the sender */
private TargetConfiguration targetConfiguration;
/** Proxy config */
private ProxyConfig proxyConfig;
// manage target connections
private TargetConnections targetConnections;
/** state of the sender */
private volatile int state = BaseConstants.STOPPED;
private String namePrefix;
private DigestGenerator digestGenerator = CachingConstants.DEFAULT_XML_IDENTIFIER;
public PassThroughHttpSender() {
log = LogFactory.getLog(this.getClass().getName());
}
protected Scheme getScheme() {
return new Scheme("http", 80, false);
}
protected ClientConnFactoryBuilder initConnFactoryBuilder(
final TransportOutDescription transportOut) throws AxisFault {
return new ClientConnFactoryBuilder(transportOut);
}
public void init(ConfigurationContext configurationContext,
TransportOutDescription transportOutDescription) throws AxisFault {
log.info("Initializing Pass-through HTTP/S Sender...");
namePrefix = transportOutDescription.getName().toUpperCase(Locale.US);
scheme = getScheme();
WorkerPool workerPool = null;
Object obj = configurationContext.getProperty(
PassThroughConstants.PASS_THROUGH_TRANSPORT_WORKER_POOL);
if (obj != null) {
workerPool = (WorkerPool) obj;
}
PassThroughTransportMetricsCollector metrics = new PassThroughTransportMetricsCollector(
false, scheme.getName());
TransportView view = new TransportView(null, this, metrics, null);
MBeanRegistrar.getInstance().registerMBean(view, "Transport",
"passthru-" + namePrefix.toLowerCase() + "-sender");
proxyConfig = new ProxyConfigBuilder().build(transportOutDescription);
log.info(proxyConfig.logProxyConfig());
targetConfiguration = new TargetConfiguration(configurationContext,
transportOutDescription, workerPool, metrics,
proxyConfig.createProxyAuthenticator());
targetConfiguration.build();
PassThroughSenderManager.registerPassThroughHttpSender(this);
configurationContext.setProperty(PassThroughConstants.PASS_THROUGH_TRANSPORT_WORKER_POOL,
targetConfiguration.getWorkerPool());
ClientConnFactoryBuilder connFactoryBuilder = initConnFactoryBuilder(transportOutDescription);
connFactory = connFactoryBuilder.createConnFactory(targetConfiguration.getHttpParams());
try {
String prefix = namePrefix + "-Sender I/O dispatcher";
ioReactor = new DefaultConnectingIOReactor(
targetConfiguration.getIOReactorConfig(),
new NativeThreadFactory(new ThreadGroup(prefix + " Thread Group"), prefix));
ioReactor.setExceptionHandler(new IOReactorExceptionHandler() {
public boolean handle(IOException ioException) {
log.warn("System may be unstable: " + namePrefix +
" ConnectingIOReactor encountered a checked exception : " +
ioException.getMessage(), ioException);
return true;
}
public boolean handle(RuntimeException runtimeException) {
log.warn("System may be unstable: " + namePrefix +
" ConnectingIOReactor encountered a runtime exception : "
+ runtimeException.getMessage(), runtimeException);
return true;
}
});
} catch (IOReactorException e) {
handleException("Error starting " + namePrefix + " ConnectingIOReactor", e);
}
ConnectCallback connectCallback = new ConnectCallback();
targetConnections = new TargetConnections(ioReactor, targetConfiguration, connectCallback);
targetConfiguration.setConnections(targetConnections);
// create the delivery agent to hand over messages
deliveryAgent = new DeliveryAgent(targetConfiguration, targetConnections, proxyConfig);
// we need to set the delivery agent
connectCallback.setDeliveryAgent(deliveryAgent);
handler = new TargetHandler(deliveryAgent, connFactory, targetConfiguration);
ioEventDispatch = new ClientIODispatch(handler, connFactory);
// start the sender in a separate thread
Thread t = new Thread(new Runnable() {
public void run() {
try {
ioReactor.execute(ioEventDispatch);
} catch (Exception ex) {
log.fatal("Exception encountered in the " + namePrefix + " Sender. " +
"No more connections will be initiated by this transport", ex);
}
log.info(namePrefix + " Sender shutdown");
}
}, "PassThrough" + namePrefix + "Sender");
t.start();
state = BaseConstants.STARTED;
log.info("Pass-through " + namePrefix + " Sender started...");
}
public void cleanup(org.apache.axis2.context.MessageContext messageContext) throws AxisFault {
}
public void stop() {
try {
ioReactor.shutdown();
} catch (IOException e) {
log.error("Error shutting down the PassThroughHttpSender", e);
}
}
public InvocationResponse invoke(org.apache.axis2.context.MessageContext msgContext) throws AxisFault {
// remove unwanted HTTP headers (if any from the current message)
PassThroughTransportUtils.removeUnwantedHeaders(msgContext, targetConfiguration);
if (AddressingHelper.isReplyRedirected(msgContext)
&& !msgContext.getReplyTo().hasNoneAddress()) {
msgContext.setProperty(PassThroughConstants.IGNORE_SC_ACCEPTED, Constants.VALUE_TRUE);
}
EndpointReference epr = PassThroughTransportUtils.getDestinationEPR(msgContext);
if (epr != null) {
if (!epr.hasNoneAddress()) {
if (msgContext.getProperty(PassThroughConstants.PASS_THROUGH_PIPE) == null) {
Pipe pipe = new Pipe(targetConfiguration.getBufferFactory().getBuffer(),
"Test", targetConfiguration);
msgContext.setProperty(PassThroughConstants.PASS_THROUGH_PIPE, pipe);
msgContext.setProperty(PassThroughConstants.MESSAGE_BUILDER_INVOKED, Boolean.TRUE);
}
deliveryAgent.submit(msgContext, epr);
sendRequestContent(msgContext);
} else {
handleException("Cannot send message to " + AddressingConstants.Final.WSA_NONE_URI);
}
} else {
if (msgContext.getProperty(Constants.OUT_TRANSPORT_INFO) != null) {
if (msgContext.getProperty(Constants.OUT_TRANSPORT_INFO) instanceof ServerWorker) {
try {
submitResponse(msgContext);
} catch (Exception e) {
handleException("Failed to submit the response", e);
}
}else {
//handleException("No valid destination EPR to send message");
//should be able to handle sendUsingOutputStream Ref NHTTP_NIO
sendUsingOutputStream(msgContext);
}
} else {
handleException("No valid destination EPR to send message");
}
}
if (msgContext.getOperationContext() != null) {
msgContext.getOperationContext().setProperty(
Constants.RESPONSE_WRITTEN, Constants.VALUE_TRUE);
}
return InvocationResponse.CONTINUE;
}
private void sendUsingOutputStream(MessageContext msgContext) throws AxisFault {
OMOutputFormat format = NhttpUtil.getOMOutputFormat(msgContext);
MessageFormatter messageFormatter =
MessageFormatterDecoratorFactory.createMessageFormatterDecorator(msgContext);
OutputStream out = (OutputStream) msgContext.getProperty(MessageContext.TRANSPORT_OUT);
if (msgContext.isServerSide()) {
OutTransportInfo transportInfo =
(OutTransportInfo) msgContext.getProperty(Constants.OUT_TRANSPORT_INFO);
if (transportInfo != null) {
transportInfo.setContentType(
messageFormatter.getContentType(msgContext, format, msgContext.getSoapAction()));
} else {
throw new AxisFault(Constants.OUT_TRANSPORT_INFO + " has not been set");
}
}
try {
messageFormatter.writeTo(msgContext, format, out, false);
out.close();
} catch (IOException e) {
handleException("IO Error sending response message", e);
}
}
private void sendRequestContent(final MessageContext msgContext) throws AxisFault {
//NOTE:this a special case where, when the backend service expects content-length but,there is no desire that the message
//should be build, if FORCE_HTTP_CONTENT_LENGTH and COPY_CONTENT_LENGTH_FROM_INCOMING, we assume that the content
//comming from the client side has not been changed
boolean forceContentLength = msgContext.isPropertyTrue(NhttpConstants.FORCE_HTTP_CONTENT_LENGTH);
boolean forceContentLengthCopy = msgContext.isPropertyTrue(PassThroughConstants.COPY_CONTENT_LENGTH_FROM_INCOMING);
if (forceContentLength && forceContentLengthCopy && msgContext.getProperty(PassThroughConstants.ORGINAL_CONTEN_LENGTH) != null) {
msgContext.setProperty(PassThroughConstants.PASSTROUGH_MESSAGE_LENGTH, Long.parseLong((String)msgContext.getProperty(PassThroughConstants.ORGINAL_CONTEN_LENGTH) ));
}
if (Boolean.TRUE.equals(msgContext.getProperty(PassThroughConstants.MESSAGE_BUILDER_INVOKED))) {
synchronized (msgContext) {
while (!Boolean.TRUE.equals(msgContext.getProperty(PassThroughConstants.WAIT_BUILDER_IN_STREAM_COMPLETE)) &&
!Boolean.TRUE.equals(msgContext.getProperty("PASSTHRU_CONNECT_ERROR"))) {
try {
msgContext.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (Boolean.TRUE.equals(msgContext.getProperty("PASSTHRU_CONNECT_ERROR"))) {
return;
}
OutputStream out = (OutputStream) msgContext.getProperty(PassThroughConstants.BUILDER_OUTPUT_STREAM);
if (out != null) {
String disableChunking = (String) msgContext.getProperty(PassThroughConstants.DISABLE_CHUNKING);
String forceHttp10 = (String) msgContext.getProperty(PassThroughConstants.FORCE_HTTP_1_0);
Pipe pipe = (Pipe) msgContext.getProperty(PassThroughConstants.PASS_THROUGH_PIPE);
if("true".equals(disableChunking) || "true".equals(forceHttp10) ){
MessageFormatter formatter = MessageFormatterDecoratorFactory.createMessageFormatterDecorator(msgContext);
OMOutputFormat format = PassThroughTransportUtils.getOMOutputFormat(msgContext);
long messageSize=0;
try {
OverflowBlob overflowBlob =setStreamAsTempData(formatter,msgContext,format);
messageSize = overflowBlob.getLength();
msgContext.setProperty(PassThroughConstants.PASSTROUGH_MESSAGE_LENGTH,messageSize);
overflowBlob.writeTo(out);
} catch (IOException e) {
// TODO Auto-generated catch block
handleException("IO while building message", e);
}
//if HTTP MEHOD = GET we need to write down the HEADER information to the wire and need
//to ignore any entity enclosed methods available.
if (("GET").equals(msgContext.getProperty(Constants.Configuration.HTTP_METHOD)) || ("DELETE").equals(msgContext.getProperty(Constants.Configuration.HTTP_METHOD))) {
pipe.setSerializationCompleteWithoutData(true);
} else if (messageSize == 0 &&
(msgContext.getProperty(PassThroughConstants.FORCE_POST_PUT_NOBODY) != null &&
(Boolean) msgContext.getProperty(PassThroughConstants.FORCE_POST_PUT_NOBODY))) {
pipe.setSerializationCompleteWithoutData(true);
} else {
pipe.setSerializationComplete(true);
}
}else {
//if HTTP MEHOD = GET we need to write down the HEADER information to the wire and need
//to ignore any entity enclosed methods available.
if (("GET").equals(msgContext.getProperty(Constants.Configuration.HTTP_METHOD)) || ("DELETE").equals(msgContext.getProperty(Constants.Configuration.HTTP_METHOD))) {
pipe.setSerializationCompleteWithoutData(true);
return;
}
if ((disableChunking == null || !"true".equals(disableChunking)) ||
(forceHttp10 == null || !"true".equals(forceHttp10))) {
MessageFormatter formatter = MessageFormatterDecoratorFactory.createMessageFormatterDecorator(msgContext);
OMOutputFormat format = PassThroughTransportUtils.getOMOutputFormat(msgContext);
formatter.writeTo(msgContext, format, out, false);
}
if ((msgContext.getProperty(PassThroughConstants.REST_GET_DELETE_INVOKE) != null &&
(Boolean) msgContext.getProperty(PassThroughConstants.REST_GET_DELETE_INVOKE))) {
pipe.setSerializationCompleteWithoutData(true);
} else if ((msgContext.getProperty(PassThroughConstants.FORCE_POST_PUT_NOBODY) != null &&
(Boolean) msgContext.getProperty(PassThroughConstants.FORCE_POST_PUT_NOBODY))) {
pipe.setSerializationCompleteWithoutData(true);
} else {
pipe.setSerializationComplete(true);
}
}
}
}
}
/**
* Write the stream to a temporary storage and calculate the content length
*
* @throws IOException if an exception occurred while writing data
*/
private OverflowBlob setStreamAsTempData(MessageFormatter messageFormatter,MessageContext msgContext,OMOutputFormat format) throws IOException {
OverflowBlob serialized = new OverflowBlob(256, 4096, "http-nio_", ".dat");
OutputStream out = serialized.getOutputStream();
try {
messageFormatter.writeTo(msgContext, format, out, false);
} finally {
out.close();
}
return serialized;
}
public void submitResponse(MessageContext msgContext)
throws IOException, HttpException {
SourceConfiguration sourceConfiguration = (SourceConfiguration) msgContext.getProperty(
PassThroughConstants.PASS_THROUGH_SOURCE_CONFIGURATION);
NHttpServerConnection conn = (NHttpServerConnection) msgContext.getProperty(
PassThroughConstants.PASS_THROUGH_SOURCE_CONNECTION);
if (conn == null) {
ServerWorker serverWorker = (ServerWorker) msgContext.getProperty(Constants.OUT_TRANSPORT_INFO);
if (serverWorker != null) {
MessageContext requestContext = serverWorker.getRequestContext();
conn = (NHttpServerConnection) requestContext.getProperty(
PassThroughConstants.PASS_THROUGH_SOURCE_CONNECTION);
sourceConfiguration = (SourceConfiguration) requestContext.getProperty(
PassThroughConstants.PASS_THROUGH_SOURCE_CONFIGURATION);
} else {
throw new IllegalStateException("Unable to correlate the response to a request");
}
}
// Handle ETag caching
if (msgContext.getProperty(PassThroughConstants.HTTP_ETAG_ENABLED) != null
&& (Boolean) msgContext.getProperty(PassThroughConstants.HTTP_ETAG_ENABLED)) {
try {
RelayUtils.buildMessage(msgContext);
} catch (IOException e) {
handleException("IO Error occurred while building the message", e);
} catch (XMLStreamException e) {
handleException("XML Error occurred while building the message", e);
}
String hash = digestGenerator.getDigest(msgContext);
Map headers = (Map) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
headers.put(HttpHeaders.ETAG,"\""+hash+"\"");
}
SourceRequest sourceRequest = SourceContext.getRequest(conn);
SourceResponse sourceResponse = SourceResponseFactory.create(msgContext,
sourceRequest, sourceConfiguration);
sourceResponse.checkResponseChunkDisable(msgContext);
SourceContext.setResponse(conn, sourceResponse);
Boolean noEntityBody = (Boolean) msgContext.getProperty(PassThroughConstants.NO_ENTITY_BODY);
Pipe pipe = (Pipe) msgContext.getProperty(PassThroughConstants.PASS_THROUGH_PIPE);
if ((noEntityBody == null || !noEntityBody) || pipe != null) {
if (pipe == null) {
pipe = new Pipe(sourceConfiguration.getBufferFactory().getBuffer(),
"Test", sourceConfiguration);
msgContext.setProperty(PassThroughConstants.PASS_THROUGH_PIPE, pipe);
msgContext.setProperty(PassThroughConstants.MESSAGE_BUILDER_INVOKED, Boolean.TRUE);
}
pipe.attachConsumer(conn);
sourceResponse.connect(pipe);
}
Integer errorCode = (Integer) msgContext.getProperty(PassThroughConstants.ERROR_CODE);
if (errorCode != null) {
sourceResponse.setStatus(HttpStatus.SC_BAD_GATEWAY);
SourceContext.get(conn).setShutDown(true);
}
ProtocolState state = SourceContext.getState(conn);
if (state != null && state.compareTo(ProtocolState.REQUEST_DONE) <= 0) {
// start sending the response if we
boolean noEntityBodyResponse = false;
if (noEntityBody != null && Boolean.TRUE == noEntityBody
&& pipe != null) {
OutputStream out = pipe.getOutputStream();
out.write(new byte[0]);
pipe.setRawSerializationComplete(true);
out.close();
noEntityBodyResponse = true;
}
if (!noEntityBodyResponse && msgContext.isPropertyTrue(PassThroughConstants.MESSAGE_BUILDER_INVOKED) && pipe != null) {
OutputStream out = pipe.getOutputStream();
/*if (msgContext.isPropertyTrue(NhttpConstants.SC_ACCEPTED)) {
out.write(new byte[0]);
}else {*/
//This is to support MTOM in response path for requests sent without a SOAPAction. The reason is
//axis2 selects application/xml formatter as the formatter for formatting the ESB to client response
//when there is no SOAPAction.
if (Constants.VALUE_TRUE.equals(msgContext.getProperty(Constants.Configuration.ENABLE_MTOM))) {
msgContext.setProperty(Constants.Configuration.CONTENT_TYPE, PassThroughConstants.CONTENT_TYPE_MULTIPART_RELATED);
msgContext.setProperty(Constants.Configuration.MESSAGE_TYPE, PassThroughConstants.CONTENT_TYPE_MULTIPART_RELATED);
}
MessageFormatter formatter = MessageFormatterDecoratorFactory.createMessageFormatterDecorator(msgContext);
OMOutputFormat format = PassThroughTransportUtils.getOMOutputFormat(msgContext);
Object contentTypeInMsgCtx =
msgContext.getProperty(org.apache.axis2.Constants.Configuration.CONTENT_TYPE);
boolean isContentTypeSetFromMsgCtx = false;
// If ContentType header is set in the axis2 message context, use it.
if (contentTypeInMsgCtx != null) {
String contentTypeValueInMsgCtx = contentTypeInMsgCtx.toString();
// Skip multipart/related as it should be taken from formatter.
if (!contentTypeValueInMsgCtx.contains(
PassThroughConstants.CONTENT_TYPE_MULTIPART_RELATED)) {
// adding charset only if charset is not available,
if (contentTypeValueInMsgCtx.indexOf(HTTPConstants.CHAR_SET_ENCODING) == -1
&& format != null) {
String encoding = format.getCharSetEncoding();
if (encoding != null) {
sourceResponse.removeHeader(HTTP.CONTENT_TYPE);
contentTypeValueInMsgCtx += "; charset=" + encoding;
}
}
sourceResponse.addHeader(HTTP.CONTENT_TYPE, contentTypeValueInMsgCtx);
isContentTypeSetFromMsgCtx = true;
}
}
// If ContentType is not set from msg context, get the formatter ContentType
if (!isContentTypeSetFromMsgCtx) {
sourceResponse.removeHeader(HTTP.CONTENT_TYPE);
sourceResponse.addHeader(HTTP.CONTENT_TYPE,
formatter.getContentType(
msgContext, format, msgContext.getSoapAction()));
}
try {
formatter.writeTo(msgContext, format, out, false);
}catch (RemoteException fault){
IOUtils.closeQuietly(out);
throw fault;
}
pipe.setSerializationComplete(true);
out.close();
}
conn.requestOutput();
} else {
// nothing much to do as we have started the response already
if (errorCode != null) {
if (log.isDebugEnabled()) {
log.warn("A Source connection is closed because of an " +
"error in target: " + conn);
}
} else {
log.debug("A Source Connection is closed, because source handler " +
"is already in the process of writing a response while " +
"another response is submitted: " + conn);
}
SourceContext.updateState(conn, ProtocolState.CLOSED);
sourceConfiguration.getSourceConnections().shutDownConnection(conn, true);
}
}
public void pause() throws AxisFault {
if (state != BaseConstants.STARTED) {
return;
}
state = BaseConstants.PAUSED;
log.info(namePrefix + " Sender Paused");
}
public void resume() throws AxisFault {
if (state != BaseConstants.PAUSED) {
return;
}
state = BaseConstants.STARTED;
log.info(namePrefix + " Sender Resumed");
}
public void maintenanceShutdown(long millis) throws AxisFault {
if (state != BaseConstants.STARTED) return;
try {
long start = System.currentTimeMillis();
ioReactor.shutdown(millis);
state = BaseConstants.STOPPED;
log.info("Sender shutdown in : " + (System.currentTimeMillis() - start) / 1000 + "s");
} catch (IOException e) {
handleException("Error shutting down the IOReactor for maintenence", e);
}
}
private void handleException(String s, Exception e) throws AxisFault {
log.error(s, e);
throw new AxisFault(s, e);
}
private void handleException(String msg) throws AxisFault {
log.error(msg);
throw new AxisFault(msg);
}
/**
* Reload SSL configurations from configurations, reset all connections and restart the thread
*
* @param transport TransportOutDescription of the configuration
* @throws AxisFault
*/
public void reloadDynamicSSLConfig(TransportOutDescription transport) throws AxisFault {
log.info("PassThroughHttpSender reloading SSL Config..");
ClientConnFactoryBuilder connFactoryBuilder = initConnFactoryBuilder(transport);
connFactory = connFactoryBuilder.createConnFactory(targetConfiguration.getHttpParams());
//Set new configurations
handler.setConnFactory(connFactory);
ioEventDispatch.setConnFactory(connFactory);
//close existing connections to apply new settings
targetConnections.resetConnectionPool(connFactory.getHostList());
log.info("Pass-through " + namePrefix + " Sender updated with Dynamic Configuration Updates ...");
}
}