/*
* Copyright 2013-2014, ApiFest project
*
* 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 com.apifest;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpClientCodec;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Client that re-sends the requests to the backend and handles the responses.
*
* @author Rossitsa Borissova
*/
public final class MappingClient {
private static final int MAX_CONTENT_LEN = 10 * 1024 * 1024;
private ClientBootstrap bootstrap;
private static volatile MappingClient client;
protected Logger log = LoggerFactory.getLogger(MappingClient.class);
private MappingClient() {
ChannelFactory factory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
bootstrap = new ClientBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("codec", new HttpClientCodec());
pipeline.addLast("aggregator", new HttpChunkAggregator(MAX_CONTENT_LEN));
pipeline.addLast("handler", new HttpResponseHandler());
return pipeline;
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.setOption("child.soLinger", -1);
bootstrap.setOption("child.connectTimeoutMillis", ServerConfig.getConnectTimeout());
}
public synchronized static MappingClient getClient() {
if (client == null) {
client = new MappingClient();
}
return client;
}
/**
* Sends the request to the given backend.
*
* @param request request that should be sent to the given backend
* @param host backend host
* @param port backend port
* @param responseListener listener that will handles the backend response
*/
public void send(final HttpRequest request, String host, int port, final ResponseListener responseListener) {
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
final Channel channel = future.getChannel();
channel.getConfig().setConnectTimeoutMillis(ServerConfig.getConnectTimeout());
if (channel.isConnected()) {
channel.getPipeline().getContext("handler").setAttachment(responseListener);
if (future.isSuccess() && channel.isOpen()) {
channel.write(request);
LifecycleEventHandlers.invokeRequestEventHandlers(request, null);
} else {
// if cannot connect
channel.disconnect();
channel.close();
HttpResponse response = HttpResponseFactory.createISEResponse();
// HttpResponse response = HttpResponseFactory.createNotFoundResponse();
responseListener.responseReceived(response);
}
} else {
channel.disconnect();
channel.close();
HttpResponse response = HttpResponseFactory.createISEResponse();
// HttpResponse response = HttpResponseFactory.createNotFoundResponse();
responseListener.responseReceived(response);
}
}
});
}
public void sendValidation(final HttpRequest request, String host, Integer port, final TokenValidationListener validatorListener) {
ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
final Channel channel = future.getChannel();
channel.getConfig().setConnectTimeoutMillis(ServerConfig.getConnectTimeout());
if (channel.isConnected()) {
channel.getPipeline().getContext("handler").setAttachment(validatorListener);
if (future.isSuccess() && channel.isOpen()) {
channel.write(request);
} else {
// if cannot connect
channel.disconnect();
channel.close();
HttpResponse response = HttpResponseFactory.createISEResponse();
// HttpResponse response = HttpResponseFactory.createNotFoundResponse();
validatorListener.responseReceived(response);
}
} else {
channel.disconnect();
channel.close();
HttpResponse response = HttpResponseFactory.createISEResponse();
// HttpResponse response = HttpResponseFactory.createNotFoundResponse();
validatorListener.responseReceived(response);
}
}
});
}
}