/*
* Copyright 2012 The Java HandlerSocket Connection Project
*
* https://github.com/komelgman/Java-HandlerSocket-Connection/
*
* The Project 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 kom.handlersocket;
import kom.handlersocket.netty.HSPipelineFactory;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.ChannelGroupFuture;
import org.jboss.netty.channel.group.ChannelGroupFutureListener;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.handler.execution.ExecutionHandler;
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
import org.jboss.netty.handler.timeout.TimeoutException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
public class HSConnectionFactory {
protected final List<HSConnectionPoint> readWriteHosts = new ArrayList<HSConnectionPoint>();
protected final List<HSConnectionPoint> readOnlyHosts = new ArrayList<HSConnectionPoint>();
protected final List<HSConnectionPoint> writeOnlyHosts = new ArrayList<HSConnectionPoint>();
protected final ClientBootstrap bootstrap;
protected final ChannelGroup channelGroup;
protected int connectionTimeout = 10000;
protected Charset charset = Charset.defaultCharset();
public HSConnectionFactory(String host) {
this(new HSConnectionPoint(host));
}
public HSConnectionFactory(HSConnectionPoint point) {
this(Arrays.asList(point));
}
public HSConnectionFactory(List<HSConnectionPoint> connectionPoints) {
for (HSConnectionPoint point : connectionPoints) {
addConnectionPoint(point);
}
channelGroup = new DefaultChannelGroup(this.getClass().getName());
bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool(),
1, // bossWorkers count
4 // ioWorkers count
));
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
}
public synchronized void addConnectionPoint(HSConnectionPoint point) {
if (point.getSupportedMode() == HSConnectionMode.READ_WRITE) {
readWriteHosts.add(point);
} else if (point.getSupportedMode() == HSConnectionMode.READ_ONLY) {
readOnlyHosts.add(point);
} else if (point.getSupportedMode() == HSConnectionMode.WRITE_ONLY) {
writeOnlyHosts.add(point);
}
}
public synchronized void removeConnectionPoint(HSConnectionPoint point) {
readWriteHosts.remove(point);
readOnlyHosts.remove(point);
writeOnlyHosts.remove(point);
}
public synchronized HSConnection connect(HSConnectionMode mode) throws TimeoutException {
HSConnection connection = new HSConnection(charset);
bootstrap.setPipelineFactory(new HSPipelineFactory(connection));
Channel channel = getChannel(mode);
channelGroup.add(channel);
connection.setChannel(channel);
return connection;
}
public synchronized ChannelGroupFuture release() {
ChannelGroupFuture result = channelGroup.close();
result.addListener(new ChannelGroupFutureListener() {
public void operationComplete(ChannelGroupFuture future) throws Exception {
bootstrap.releaseExternalResources();
}
});
return result;
}
private Channel getChannel(HSConnectionMode mode) {
HSConnectionPoint connectionPoint = getConnectionPoint(mode);
ChannelFuture channelFuture = bootstrap.connect(
new InetSocketAddress(
connectionPoint.getHost(),
connectionPoint.getPort(mode)));
if (!channelFuture.awaitUninterruptibly(connectionTimeout)) {
throw new TimeoutException();
}
if (!channelFuture.isSuccess()) {
// todo: throw 'connection error'
}
return channelFuture.getChannel();
}
// simple load balancing
protected HSConnectionPoint getConnectionPoint(HSConnectionMode mode) {
if (HSConnectionMode.READ_WRITE == mode) {
return getRandomHost(readWriteHosts);
} else if (HSConnectionMode.READ_ONLY == mode) {
return getRandomHost(readOnlyHosts);
} else if (HSConnectionMode.WRITE_ONLY == mode) {
return getRandomHost(writeOnlyHosts);
}
throw new IllegalArgumentException();
}
protected HSConnectionPoint getRandomHost(List<HSConnectionPoint> collection) {
return collection.get((int) (Math.random() * (collection.size() - 1)));
}
public void setConnectionTimeout(int timeout) {
connectionTimeout = timeout;
}
public int getConnectionTimeout() {
return connectionTimeout;
}
public void setCharset(Charset charset) {
this.charset = charset;
}
public Charset getCharset() {
return charset;
}
}