/*
* Copyright 2014 Matthias Einwag
*
* The jawampa authors license 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 ws.wamp.jawampa.transport;
import java.net.URI;
import javax.net.ssl.SSLException;
import ws.wamp.jawampa.ApplicationError;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler;
import io.netty.handler.codec.http.websocketx.WebSocketFrameAggregator;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
/**
* Returns factory methods for the establishment of WAMP connections between
* clients and routers.<br>
*/
public class WampClientChannelFactoryResolver {
public static WampClientChannelFactory getFactory(final URI uri, final SslContext sslCtx) throws ApplicationError
{
String scheme = uri.getScheme();
scheme = scheme != null ? scheme : "";
if (scheme.equalsIgnoreCase("ws") || scheme.equalsIgnoreCase("wss")) {
// Check the host and port field for validity
if (uri.getHost() == null || uri.getPort() == 0) {
throw new ApplicationError(ApplicationError.INVALID_URI);
}
// Return a factory that creates a channel for websocket connections
return new WampClientChannelFactory() {
@Override
public ChannelFuture createChannel(final ChannelHandler handler,
final EventLoopGroup eventLoop,
final ObjectMapper objectMapper)
throws Exception
{
// Initialize SSL when required
final boolean needSsl = uri.getScheme().equalsIgnoreCase("wss");
final SslContext sslCtx0;
if (needSsl && sslCtx == null) {
// Create a default SslContext when we got none provided through the constructor
try {
sslCtx0 = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
}
catch (SSLException e) {
throw e;
}
} else if (needSsl) {
sslCtx0 = sslCtx;
} else {
sslCtx0 = null;
}
// Use well-known ports if not explicitly specified
final int port;
if (uri.getPort() == -1) {
if (needSsl) port = 443;
else port = 80;
} else port = uri.getPort();
final WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, WampHandlerConfiguration.WAMP_WEBSOCKET_PROTOCOLS,
false, new DefaultHttpHeaders());
Bootstrap b = new Bootstrap();
b.group(eventLoop)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
if (sslCtx0 != null) {
p.addLast(sslCtx0.newHandler(ch.alloc(),
uri.getHost(),
port));
}
p.addLast(
new HttpClientCodec(),
new HttpObjectAggregator(8192),
new WebSocketClientProtocolHandler(handshaker, false),
new WebSocketFrameAggregator(WampHandlerConfiguration.MAX_WEBSOCKET_FRAME_SIZE),
new WampClientWebsocketHandler(handshaker, objectMapper),
handler);
}
});
return b.connect(uri.getHost(), port);
}
};
}
throw new ApplicationError(ApplicationError.INVALID_URI);
}
}