/** * */ package com.trendrr.strest.contrib.zmq; import java.nio.ByteBuffer; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.trendrr.oss.Timeframe; import com.trendrr.oss.exceptions.TrendrrException; import com.trendrr.strest.server.connections.StrestConnectionChannel; import com.trendrr.strest.server.v2.models.StrestResponse; import com.trendrr.strest.server.v2.models.json.StrestJsonResponse; import com.trendrr.zmq.server.ZMQChannel; /** * @author Dustin Norlander * @created Jun 4, 2012 * */ public class StrestZMQChannel extends StrestConnectionChannel{ protected static Log log = LogFactory.getLog(StrestZMQChannel.class); protected ZMQChannel channel; protected Date lastMessage; //last time we recieved a message from the client. protected int timeoutSeconds; //number of seconds we consider this connection to be dead if no incoming message recieved. protected StrestZMQChannel(ZMQChannel channel) { super(); this.channel = channel; } /** * Mapping from zmq id to the subsequent strest channel. * */ protected static ConcurrentHashMap<ByteBuffer,StrestZMQChannel> channels = new ConcurrentHashMap<ByteBuffer,StrestZMQChannel>(); /** * gets the StrestNettyConnectionChannel based on the channel, or creates a new association. * @param channel */ public static StrestZMQChannel get(ZMQChannel channel) { ByteBuffer id = ByteBuffer.wrap(channel.getId()); //we wrap in a byte buffer because hashcode in byte[] doesn't work by val (works by address) StrestZMQChannel c= channels.get(id); if (c == null) { channels.putIfAbsent(id, new StrestZMQChannel(channel)); return channels.get(id); } return c; } /** * runs the connection reaper. removes any connections that have timedout. * @return */ public static void reaper() { log.warn("*** Running ZMQ Connection Reaper ****"); for (StrestZMQChannel c : channels.values()) { if (!c.isConnected()) { log.warn("*** REAPING: " + c); c.cleanup(); } } log.warn("*** DONE ZMQ Connection Reaper ****"); } public ZMQChannel getChannel() { return this.channel; } /* (non-Javadoc) * @see com.trendrr.strest.server.connections.StrestConnectionChannel#isConnected() */ @Override public boolean isConnected() { return (this.getLastIncoming().after(Timeframe.SECONDS.add(new Date(), -this.timeoutSeconds))); } /* (non-Javadoc) * @see com.trendrr.strest.server.connections.StrestConnectionChannel#doSendMessage(com.trendrr.strest.server.v2.models.StrestResponse) */ @Override protected Object doSendMessage(StrestResponse response) throws Exception { if (response instanceof StrestJsonResponse) { channel.send(((StrestJsonResponse)response).toByteArray()); } else { throw new TrendrrException("Invalid response type: " + response.getClass()); } return null; } /* (non-Javadoc) * @see com.trendrr.strest.server.connections.StrestConnectionChannel#getRemoteAddress() */ @Override public String getRemoteAddress() { return null; } @Override public void cleanup() { super.cleanup(); channels.remove(this.channel.getId()); //TODO: no way to disconnect a client from the server? } /** * a message has been recieved, this resets our counter. */ public synchronized void setLastIncoming() { this.lastMessage = new Date(); } public synchronized Date getLastIncoming() { return this.lastMessage; } }