/** * Copyright (c) 2015, 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.wso2.carbon.websocket.transport; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; import org.apache.axiom.om.OMOutputFormat; import org.apache.axis2.AxisFault; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.MessageContext; import org.apache.axis2.description.TransportOutDescription; import org.apache.axis2.transport.MessageFormatter; import org.apache.axis2.transport.OutTransportInfo; import org.apache.axis2.transport.base.AbstractTransportSender; import org.apache.axis2.transport.base.BaseUtils; import org.apache.axis2.util.MessageProcessorSelector; import org.apache.commons.io.output.WriterOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.core.axis2.Axis2MessageContext; import org.apache.synapse.inbound.InboundEndpointConstants; import org.apache.synapse.inbound.InboundResponseSender; import org.apache.synapse.transport.passthru.util.RelayUtils; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import javax.xml.stream.XMLStreamException; import java.io.IOException; import java.io.OutputStream; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; public class WebsocketTransportSender extends AbstractTransportSender { private WebsocketConnectionFactory connectionFactory; private static final Log log = LogFactory.getLog(WebsocketTransportSender.class); public void init(ConfigurationContext cfgCtx, TransportOutDescription transportOut) throws AxisFault { if (log.isDebugEnabled()) { log.debug("Initializing WS Connection Factory."); } super.init(cfgCtx, transportOut); connectionFactory = WebsocketConnectionFactory.getInstance(transportOut); } public void sendMessage(MessageContext msgCtx, String targetEPR, OutTransportInfo trpOut) throws AxisFault { String sourceIdentier = null; boolean handshakePresent = false; String responceDispatchSequence = null; String responceErrorSequence = null; String messageType = null; InboundResponseSender responseSender = null; if (msgCtx.getProperty(InboundEndpointConstants.INBOUND_ENDPOINT_RESPONSE_WORKER) != null) { responseSender = (InboundResponseSender) msgCtx.getProperty(InboundEndpointConstants.INBOUND_ENDPOINT_RESPONSE_WORKER); sourceIdentier = ((ChannelHandlerContext) msgCtx. getProperty(WebsocketConstants.WEBSOCKET_SOURCE_HANDLER_CONTEXT)).channel().toString(); } else { sourceIdentier = WebsocketConstants.UNIVERSAL_SOURCE_IDENTIFIER; } if (msgCtx.getProperty(WebsocketConstants.WEBSOCKET_SOURCE_HANDSHAKE_PRESENT) != null && msgCtx.getProperty(WebsocketConstants.WEBSOCKET_SOURCE_HANDSHAKE_PRESENT).equals(true)) { handshakePresent = true; } if (msgCtx.getProperty(WebsocketConstants.WEBSOCKET_OUTFLOW_DISPATCH_SEQUENCE) != null) { responceDispatchSequence = (String) msgCtx.getProperty(WebsocketConstants.WEBSOCKET_OUTFLOW_DISPATCH_SEQUENCE); } if (msgCtx.getProperty(WebsocketConstants.WEBSOCKET_OUTFLOW_DISPATCH_FAULT_SEQUENCE) != null) { responceErrorSequence = (String) msgCtx.getProperty(WebsocketConstants.WEBSOCKET_OUTFLOW_DISPATCH_FAULT_SEQUENCE); } if (msgCtx.getProperty(WebsocketConstants.CONTENT_TYPE) != null) { messageType = (String) msgCtx.getProperty(WebsocketConstants.CONTENT_TYPE); } try { if (log.isDebugEnabled()) { log.debug("Fetching a Connection from the WS(WSS) Connection Factory."); } WebSocketClientHandler clientHandler = connectionFactory.getChannelHandler(new URI(targetEPR), sourceIdentier, handshakePresent, responceDispatchSequence, responceErrorSequence, messageType); String tenantDomain = (String) msgCtx.getProperty(MultitenantConstants.TENANT_DOMAIN); if (tenantDomain != null) { clientHandler.setTenantDomain(tenantDomain); } else { clientHandler.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); } if (!sourceIdentier.equals(WebsocketConstants.UNIVERSAL_SOURCE_IDENTIFIER)) { clientHandler.registerWebsocketResponseSender(responseSender); clientHandler.setDispatchSequence(responceDispatchSequence); clientHandler.setDispatchErrorSequence(responceErrorSequence); } if (msgCtx.getProperty(WebsocketConstants.WEBSOCKET_BINARY_FRAME_PRESENT) != null && msgCtx.getProperty(WebsocketConstants.WEBSOCKET_BINARY_FRAME_PRESENT).equals(true)) { WebSocketFrame frame = (BinaryWebSocketFrame) msgCtx.getProperty(WebsocketConstants.WEBSOCKET_BINARY_FRAME); if (log.isDebugEnabled()) { log.debug("Sending the binary frame to the WS server on context id : " + clientHandler.getChannelHandlerContext().channel().toString()); } if (clientHandler.getChannelHandlerContext().channel().isActive()) { clientHandler.getChannelHandlerContext().channel().writeAndFlush(frame.retain()); } } else if (msgCtx.getProperty(WebsocketConstants.WEBSOCKET_TEXT_FRAME_PRESENT) != null && msgCtx.getProperty(WebsocketConstants.WEBSOCKET_TEXT_FRAME_PRESENT).equals(true)) { WebSocketFrame frame = (TextWebSocketFrame) msgCtx.getProperty(WebsocketConstants.WEBSOCKET_TEXT_FRAME); if (log.isDebugEnabled()) { log.debug("Sending the passthrough text frame to the WS server on context id : " + clientHandler.getChannelHandlerContext().channel().toString()); } if (clientHandler.getChannelHandlerContext().channel().isActive()) { clientHandler.getChannelHandlerContext().channel().writeAndFlush(frame.retain()); } } else { if (!handshakePresent) { RelayUtils.buildMessage(msgCtx, false); OMOutputFormat format = BaseUtils.getOMOutputFormat(msgCtx); MessageFormatter messageFormatter = MessageProcessorSelector.getMessageFormatter(msgCtx); StringWriter sw = new StringWriter(); OutputStream out = new WriterOutputStream(sw, format.getCharSetEncoding()); messageFormatter.writeTo(msgCtx, format, out, true); out.close(); final String msg = sw.toString(); WebSocketFrame frame = new TextWebSocketFrame(msg); if (log.isDebugEnabled()) { log.debug("Sending the text frame to the WS server on context id : " + clientHandler.getChannelHandlerContext().channel().toString()); } if (clientHandler.getChannelHandlerContext().channel().isActive()) { clientHandler.getChannelHandlerContext().channel().writeAndFlush(frame.retain()); } } else { clientHandler.acknowledgeHandshake(); } } } catch (URISyntaxException e) { log.error("Error parsing the WS endpoint url", e); } catch (IOException e) { log.error("Error writting to the websocket channel", e); } catch (InterruptedException e) { log.error("Error writting to the websocket channel", e); } catch (XMLStreamException e) { handleException("Error while building message", e); } } }