package org.juxtapose.streamline.util.net; import java.util.HashMap; import java.util.Map; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import org.juxtapose.streamline.producer.ISTMEntryKey; import org.juxtapose.streamline.protocol.message.PostMarshaller; import org.juxtapose.streamline.protocol.message.PreMarshaller; import org.juxtapose.streamline.protocol.message.StreamDataProtocol.DataKey; import org.juxtapose.streamline.protocol.message.StreamDataProtocol.DataMap; import org.juxtapose.streamline.protocol.message.StreamDataProtocol.Message; import org.juxtapose.streamline.protocol.message.StreamDataProtocol.SubQueryResponseMessage; import org.juxtapose.streamline.protocol.message.StreamDataProtocol.UpdateMessage; import org.juxtapose.streamline.stm.ISTM; import org.juxtapose.streamline.util.ISTMRequestor; import org.juxtapose.streamline.util.Status; import org.juxtapose.streamline.util.data.DataType; import static org.juxtapose.streamline.tools.Preconditions.*; import com.sun.istack.internal.NotNull; import com.trifork.clj_ds.IPersistentMap; import com.trifork.clj_ds.PersistentHashMap; /** * @author Pontus J�rgne * 2 maj 2013 * Copyright (c) Pontus J�rgne. All rights reserved */ public class ClientConnectorHandler extends SimpleChannelUpstreamHandler { private final ISTM stm; RemoteServiceTracker serviceTracker; ReferenceStore refStore = new ClientReferenceStore(); HashMap<Object, RemoteServiceProxy> tagToService = new HashMap<Object, RemoteServiceProxy>(); Channel channel; HashMap<ISTMEntryKey, RemoteProxyEntryProducer> keyToSubscriber = new HashMap<ISTMEntryKey, RemoteProxyEntryProducer>(); /**TICKET This needs to be handled more appropriately with a unique request id mapped to the individual clients request tag**/ Integer tagInc = 0; HashMap<Integer, Object> tagRefToTag = new HashMap<Integer, Object>(); HashMap<Integer, Object> requestToTag = new HashMap<Integer, Object>(); public ClientConnectorHandler( ISTM inSTM ) { stm = inSTM; } @Override public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof ChannelStateEvent) { } super.handleUpstream(ctx, e); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) { stm.logInfo("Connection recieved.."); channel = ctx.getChannel(); serviceTracker = new RemoteServiceTracker( stm, this ); } @Override public void channelInterestChanged(ChannelHandlerContext ctx, ChannelStateEvent e) { } @Override public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) { Message message = (Message)e.getMessage(); if( message.getType() == Message.Type.SubQueryResponseMessage ) { SubQueryResponseMessage subMess = message.getSubQueryResponseMessage(); int statusInt = subMess.getStatus(); Status status = Status.values()[statusInt]; int ref = subMess.getReference(); int tag = subMess.getTag(); DataKey dataKey = subMess.getKey(); ISTMEntryKey key = null; if( dataKey != null ) { key = PostMarshaller.parseKey( dataKey ); } DataMap data = subMess.getData(); IPersistentMap<String, DataType<?>> pData = null; if( data != null ) { pData = PersistentHashMap.EMPTY; pData = PostMarshaller.parseDataMap( data, pData ); } queryResponse( status, key, ref, tag, pData ); } else if( message.getType() == Message.Type.UpdateMessage ) { UpdateMessage update = message.getUpdateMessage(); int reference = update.getReference(); boolean fullUpdate = update.hasFullupdate() ? update.getFullupdate() : true; ISTMEntryKey key = refStore.getKeyFromRef( reference ); if( key == null ) { stm.logError( "Key for ref "+reference+" not found" ); return; } DataMap data = update.getData(); RemoteProxyEntryProducer producer = keyToSubscriber.get( key ); if( producer == null ) { stm.logError( "Remote entry Producer for key "+key+" not found" ); return; } IPersistentMap<String, DataType<?>> map = PersistentHashMap.emptyMap(); map = PostMarshaller.parseDataMap( data, map ); producer.updateData( key, map, fullUpdate ); } } /** * @param inSubscriber * @param inService * @param inQuery * @param inTag */ public void requestKey( RemoteServiceProxy inProxy, String inService, Map<String, String> inQuery, Object inTag) { Integer tagRef = tagInc++; tagRefToTag.put( tagRef, inTag ); tagToService.put( tagRef, inProxy ); Message mess = PreMarshaller.createSubQuery( inService, tagRef, inQuery ); channel.write(mess); } /** * @param inStatus * @param inKey * @param inRef * @param inTag * @param inData */ public void queryResponse( Status inStatus, ISTMEntryKey inKey, Integer inRef, Integer inTag, IPersistentMap<String, DataType<?>> inData ) { Object tag = tagRefToTag.remove( inTag ); if( tag == null ) { stm.logError( "Tag for tagRef "+inTag+" could not be found"); return; } RemoteServiceProxy service = tagToService.remove( inTag ); notNull( service ); refStore.addReference( inRef, inKey ); service.remoteKeyDelivered( inKey, tag ); } /** * @param inSubscriber * @param inKey */ public void subscribe( RemoteProxyEntryProducer inProducer, ISTMEntryKey inKey ) { Integer ref = refStore.getRefFromKey( inKey ); Message subMessage; if( ref == null ) { //Optimistic request ref = refStore.addReference( inKey ); subMessage = PreMarshaller.createSubscriptionMessage( ref, inKey ); } else { subMessage = PreMarshaller.createSubscriptionMessage( ref ); } keyToSubscriber.put( inKey, inProducer ); channel.write( subMessage ); } /** * @param inTag * @param inRequestor * @param inVariable * @param inData */ public void request( int inTag, long inType, ISTMRequestor inRequestor, String inService, String inVariable, IPersistentMap<String, DataType<?>> inData ) { requestToTag.put( inTag, inRequestor ); Message mess = PreMarshaller.createRequestMessage( inTag, inType, inService, inVariable, inData ); channel.write( mess ); } /* (non-Javadoc) * @see org.jboss.netty.channel.SimpleChannelUpstreamHandler#exceptionCaught(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ExceptionEvent) */ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { stm.logError(e.toString(), e.getCause()); } }