/*******************************************************************************
* gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/
* Copyright (C) 2014 SVS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package userGeneratedContent.testbedPlugIns.layerPlugIns.layer1network.cascade_TCP_v0_001;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.BufferUnderflowException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.IOStrategy;
import org.glassfish.grizzly.filterchain.BaseFilter;
import org.glassfish.grizzly.filterchain.FilterChainBuilder;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
import org.glassfish.grizzly.filterchain.TransportFilter;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;
import org.glassfish.grizzly.strategies.WorkerThreadIOStrategy;
import staticContent.framework.controller.SubImplementation;
import staticContent.framework.message.MixMessage;
import staticContent.framework.message.Request;
import staticContent.framework.userDatabase.User;
import staticContent.framework.util.Util;
// TODO: may block in duplex mode...n
public class ClientHandler_TCP_FCFS_async_grizzly extends SubImplementation {
private int port;
private InetAddress bindAddress;
private int backlog;
private int maxRequestLength;
private ConcurrentMap<User, Connection<?>> usermap;
private int QUEUE_BLOCK_SIZE;
/**
* @see framework.ThreePhaseStart#constructor()
*/
@Override
public void constructor() {
this.bindAddress = settings.getPropertyAsInetAddress("GLOBAL_MIX_BIND_ADDRESS");
this.port = settings.getPropertyAsInt("GLOBAL_MIX_BIND_PORT");
this.backlog = settings.getPropertyAsInt("BACKLOG");
this.maxRequestLength = settings.getPropertyAsInt("MAX_REQUEST_LENGTH");
this.usermap = new ConcurrentHashMap<User, Connection<?>>();
this.QUEUE_BLOCK_SIZE = settings.getPropertyAsInt("GLOBAL_QUEUE_BLOCK_SIZE");
}
/**
* @see framework.ThreePhaseStart#initialize()
*/
@Override
public void initialize() {
}
/**
* @see framework.ThreePhaseStart#begin()
*/
@Override
public void begin() {
final IOStrategy iostrategy = WorkerThreadIOStrategy.getInstance();
final FilterChainBuilder filterChainBuilder = FilterChainBuilder.stateless();
final TCPNIOTransport transport = TCPNIOTransportBuilder.newInstance().build();
filterChainBuilder.add(new TransportFilter());
filterChainBuilder.add(new Filter());
transport.setKeepAlive(true);
transport.setProcessor(filterChainBuilder.build());
transport.setIOStrategy(iostrategy);
try {
transport.bind(this.bindAddress.getHostAddress(), this.port, this.backlog);
transport.start();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Could not open ServerSocket.");
}
}
/**
* Implements the protocol logic.
*
* @author Christopher Bartz
*
*/
private class Filter extends BaseFilter {
int counter = 0;
Map<Connection<?>, User> connMap = new HashMap<Connection<?>, User>();
@Override
public NextAction handleRead(FilterChainContext ctx) throws IOException {
Buffer buf = (Buffer) ctx.getMessage(); /*
* we assume a Buffer
* because we have a
* TransportFilter before us
* in the chain
*/
Connection<?> conn = ctx.getConnection();
byte[] msg;
List<Request> requestList = new ArrayList<Request>(QUEUE_BLOCK_SIZE);
byte[] msgLengthArray = new byte[4];
/* fetch up to QUEUE_BLOCK_SIZE messages and put them in the queue */
while (buf.remaining() >= 4) {
/*
* we remember our current position, so we will be able to reset
* after an BufferUnderflow
*/
int startposition = buf.position();
buf.get(msgLengthArray);
int msgLength = Util.byteArrayToInt(msgLengthArray);
if (buf.remaining() < msgLength) {
buf.position(startposition);
buf.shrink();
if (requestList.size() > 0) {
anonNode.putInRequestInputQueue(requestList.toArray(new Request[0]));
}
return ctx.getStopAction(buf);
}
if (msgLength > maxRequestLength) {
buf.position(startposition + 4 + msgLength);
System.err.println("warning: user " + connMap.get(conn) + " sent a too large message");
} else {
msg = new byte[msgLength];
try {
buf.get(msg, 0, msgLength);
Request request = MixMessage.getInstanceRequest(msg,
connMap.get(conn));
requestList.add(request);
if (requestList.size() >= QUEUE_BLOCK_SIZE) {
anonNode.putInRequestInputQueue(requestList.toArray(new Request[0]));
requestList.clear();
}
} catch (BufferUnderflowException e) {
buf.position(startposition);
buf.shrink();
if (requestList.size() > 0) {
anonNode.putInRequestInputQueue(requestList.toArray(new Request[0]));
}
return ctx.getStopAction(buf);
}
}
}
if (requestList.size() > 0) {
anonNode.putInRequestInputQueue(requestList.toArray(new Request[0]));
}
/* if we have up to 3 bytes remaining, we need to store the buffer */
if (buf.remaining() > 0) {
buf.shrink();
return ctx.getStopAction(buf);
} else {
return ctx.getStopAction();
}
}
@Override
public NextAction handleAccept(FilterChainContext ctx)
throws IOException {
if (++counter % 100 == 0)
System.out.println(counter + " connections accepted");
User user = userDatabase.generateUser();
userDatabase.addUser(user);
usermap.putIfAbsent(user, ctx.getConnection());
connMap.put(ctx.getConnection(), user);
return ctx.getStopAction();
}
}
}