Axis2HttpTransportSender.java
/*
* Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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.netty.sender;
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.TransportSender;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.transport.netty.BridgeConstants;
import org.apache.synapse.transport.netty.config.TargetConfiguration;
import org.apache.synapse.transport.netty.util.HttpUtils;
import org.apache.synapse.transport.netty.util.RequestResponseUtils;
import org.wso2.transport.http.netty.contract.HttpClientConnector;
import org.wso2.transport.http.netty.contract.HttpWsConnectorFactory;
import org.wso2.transport.http.netty.contractimpl.DefaultHttpWsConnectorFactory;
import org.wso2.transport.http.netty.contractimpl.sender.channel.BootstrapConfiguration;
import org.wso2.transport.http.netty.contractimpl.sender.channel.pool.ConnectionManager;
import org.wso2.transport.http.netty.message.Http2PushPromise;
import org.wso2.transport.http.netty.message.HttpCarbonMessage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
/**
* {@code Axis2HttpTransportSender} receives the outgoing axis2 {@code MessageContext}, convert it into a
* {@code HttpCarbonMessage} and deliver it to the Http Client connector.
*/
public class Axis2HttpTransportSender extends AbstractHandler implements TransportSender {
private static final Log LOG = LogFactory.getLog(Axis2HttpTransportSender.class);
/**
* The instance that handles connection pool management.
*/
ConnectionManager connectionManager;
/**
* This instance can be used to create client connectors.
*/
HttpWsConnectorFactory httpWsConnectorFactory;
protected TargetConfiguration targetConfiguration;
BootstrapConfiguration bootstrapConfiguration;
@Override
public void init(ConfigurationContext configurationContext, TransportOutDescription transportOutDescription)
throws AxisFault {
httpWsConnectorFactory = new DefaultHttpWsConnectorFactory();
connectionManager = HttpUtils.getConnectionManager();
bootstrapConfiguration = new BootstrapConfiguration(new HashMap<>());
targetConfiguration = new TargetConfiguration(configurationContext, transportOutDescription);
targetConfiguration.build();
}
@Override
public InvocationResponse invoke(MessageContext msgCtx) throws AxisFault {
if (AddressingHelper.isReplyRedirected(msgCtx)) {
msgCtx.setProperty(BridgeConstants.IGNORE_SC_ACCEPTED, BridgeConstants.VALUE_TRUE);
}
EndpointReference destinationEPR = RequestResponseUtils.getDestinationEPR(msgCtx);
if (isRequestToBackend(destinationEPR)) {
try {
URL destinationURL = new URL(destinationEPR.getAddress());
sendRequestToBackendService(msgCtx, destinationURL);
} catch (MalformedURLException e) {
handleException("Malformed URL in the target EPR", e);
} catch (IOException e) {
handleException("Error while sending the request to the backend service "
+ destinationEPR.getAddress(), e);
}
} else {
HttpCarbonMessage clientRequest =
(HttpCarbonMessage) msgCtx.getProperty(BridgeConstants.HTTP_CLIENT_REQUEST_CARBON_MESSAGE);
if (clientRequest == null) {
LOG.warn("Unable to find the original client request to send the response");
return InvocationResponse.ABORT;
}
if (isPushPromise(msgCtx)) {
pushPromiseToClient(msgCtx, clientRequest);
} else if (isServerPush(msgCtx)) {
pushResponseToClient(msgCtx, clientRequest);
} else {
try {
sendResponseToClient(msgCtx, clientRequest);
if (msgCtx.getOperationContext() != null) {
msgCtx.getOperationContext().setProperty(Constants.RESPONSE_WRITTEN, Constants.VALUE_TRUE);
}
} catch (IOException e) {
handleException("Error occurred while sending a response to the client", e);
}
}
}
return InvocationResponse.CONTINUE;
}
private boolean isRequestToBackend(EndpointReference destinationEPR) throws AxisFault {
if (destinationEPR != null) {
if (destinationEPR.hasNoneAddress()) {
handleException("Cannot send the message to " + AddressingConstants.Final.WSA_NONE_URI);
}
return true;
}
return false;
}
/**
* Checks whether the message is a response or server push response.
*
* @param msgCtx axis2 message context
* @return boolean
*/
private boolean isServerPush(MessageContext msgCtx) {
return msgCtx.isPropertyTrue(BridgeConstants.SERVER_PUSH);
}
/**
* Checks whether the message is a response or server push promise.
*
* @param msgCtx axis2 message context
* @return boolean
*/
private boolean isPushPromise(MessageContext msgCtx) {
return msgCtx.isPropertyTrue(BridgeConstants.IS_PUSH_PROMISE);
}
/**
* Submits a response back to the client.
*
* @param msgCtx axis2 message context
* @param clientRequest original HTTP carbon request
* @throws AxisFault if something goes wrong when creating the outbound response or responding back to the client
*/
private void sendResponseToClient(MessageContext msgCtx, HttpCarbonMessage clientRequest) throws AxisFault {
HttpCarbonMessage outboundResponseMsg = SourceResponseHandler.createOutboundResponseMsg(msgCtx, clientRequest);
SourceResponseHandler.sendResponse(msgCtx, clientRequest, outboundResponseMsg);
}
/**
* Send the server push promise to client.
*
* @param msgCtx axis2 message context
* @param clientRequest HttpCarbonMessage
* @throws AxisFault throws if error occurred while sending server pushes
*/
private void pushPromiseToClient(MessageContext msgCtx, HttpCarbonMessage clientRequest) throws AxisFault {
Http2PushPromise http2PushPromise = SourceResponseHandler.getPushPromise(msgCtx);
SourceResponseHandler.pushPromise(http2PushPromise, clientRequest);
}
/**
* Send the server push response to client.
*
* @param msgCtx axis2 message context
* @param clientRequest HttpCarbonMessage
* @throws AxisFault throws if error occurred while sending server pushes
*/
private void pushResponseToClient(MessageContext msgCtx, HttpCarbonMessage clientRequest) throws AxisFault {
Http2PushPromise http2PushPromise = SourceResponseHandler.getPushPromise(msgCtx);
HttpCarbonMessage outboundPushMsg = SourceResponseHandler.createOutboundResponseMsg(msgCtx, clientRequest);
SourceResponseHandler.pushResponse(msgCtx, http2PushPromise, outboundPushMsg, clientRequest);
}
/**
* Sends an outbound request to the backend service.
*
* @param msgCtx axis2 message context
* @param url request URL of the backend service
* @throws IOException if something goes wrong when sending the outbound request to the backend service
*/
private void sendRequestToBackendService(MessageContext msgCtx, URL url) throws IOException {
HttpCarbonMessage outboundRequestMsg = TargetRequestHandler.createOutboundRequestMsg(url, msgCtx,
targetConfiguration);
HttpClientConnector clientConnector = TargetRequestHandler.createHttpClient(url, msgCtx,
httpWsConnectorFactory, connectionManager, bootstrapConfiguration, targetConfiguration);
TargetRequestHandler.sendRequest(clientConnector, outboundRequestMsg, msgCtx, targetConfiguration);
}
@Override
public void cleanup(MessageContext messageContext) {
}
@Override
public void stop() {
}
public void handleException(String s, Exception e) throws AxisFault {
LOG.error(s, e);
throw new AxisFault(s, e);
}
public void handleException(String msg) throws AxisFault {
LOG.error(msg);
throw new AxisFault(msg);
}
}