Package io.reactivex.netty

Source Code of io.reactivex.netty.RxEventPipelineConfigurator

/*
* Copyright 2014 Netflix, Inc.
*
* 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 io.reactivex.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.reactivex.netty.pipeline.PipelineConfigurator;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class RxEventPipelineConfigurator implements PipelineConfigurator<RemoteRxEvent, RemoteRxEvent>{

    private static final Logger logger = LoggerFactory.getLogger(RxEventPipelineConfigurator.class);
  private static final byte PROTOCOL_VERSION = 1;
 
  @Override
  public void configureNewPipeline(ChannelPipeline pipeline) {
    pipeline.addLast(new ChannelDuplexHandler(){

      @Override
      public void channelRead(ChannelHandlerContext ctx, Object msg)
          throws Exception {
        boolean handled = false;
        if (ByteBuf.class.isAssignableFrom(msg.getClass())) {
                    ByteBuf byteBuf = (ByteBuf) msg;
                    if (byteBuf.isReadable()) {
                        int protocolVersion = byteBuf.readByte();
                        if (protocolVersion != PROTOCOL_VERSION){
                          throw new RuntimeException("Unsupported protocol version: "+protocolVersion);
                        }
                        int observableNameLength = byteBuf.readByte();
                        String observableName = null;
                        if (observableNameLength > 0){
                          // read name
                          observableName = new String(byteBuf.readBytes(observableNameLength).array());
                        }
                        int operation = byteBuf.readByte();
                        RemoteRxEvent.Type type = null;
                        Map<String,String> subscribeParams = null;
                        byte[] valueData = null;
                        if (operation == 1){
                          logger.debug("READ request for RemoteRxEvent: next");
                          type = RemoteRxEvent.Type.next;
                          valueData = new byte[byteBuf.readableBytes()];
                            byteBuf.readBytes(valueData);
                        }else if (operation == 2){
                          logger.debug("READ request for RemoteRxEvent: error");
                          type = RemoteRxEvent.Type.error;
                          valueData = new byte[byteBuf.readableBytes()];
                            byteBuf.readBytes(valueData);
                        }else if (operation == 3){
                          logger.debug("READ request for RemoteRxEvent: completed");
                          type = RemoteRxEvent.Type.completed;
                        }else if (operation == 4){
                          logger.debug("READ request for RemoteRxEvent: subscribed");
                          type = RemoteRxEvent.Type.subscribed;
                          // read subscribe parameters
                          int subscribeParamsLength = byteBuf.readInt();
                          if (subscribeParamsLength > 0){
                            // read byte into map
                            byte[] subscribeParamsBytes = new byte[subscribeParamsLength];
                            byteBuf.readBytes(subscribeParamsBytes);
                            subscribeParams = fromBytesToMap(subscribeParamsBytes);
                          }
                        }else if (operation == 5){
                          logger.debug("READ request for RemoteRxEvent: unsubscribed");
                          type = RemoteRxEvent.Type.unsubscribed;
                        }else{
                          throw new RuntimeException("operation: "+operation+" not support.");
                        }
                        handled = true;
                        byteBuf.release();
                        ctx.fireChannelRead(new RemoteRxEvent(observableName, type, valueData, subscribeParams));                       
                    }
        }
        if (!handled){
          super.channelRead(ctx, msg);
        }
      }

      @Override
      public void write(ChannelHandlerContext ctx, Object msg,
          ChannelPromise promise) throws Exception {
        if (msg instanceof RemoteRxEvent){
          ByteBuf buf = ctx.alloc().buffer();
          buf.writeByte(PROTOCOL_VERSION);
          RemoteRxEvent event = (RemoteRxEvent) msg;
          String observableName = event.getName();
          if (observableName != null && !observableName.isEmpty()){
            // write length
            int nameLength = observableName.length();
            if (nameLength < 127){
              buf.writeByte(nameLength);
              buf.writeBytes(observableName.getBytes());
            }else{
              throw new RuntimeException("observableName "+observableName+
                  " exceeds max limit of 127 characters");
            }
          }else{
            // no name provided, write 0 bytes for name length
            buf.writeByte(0);
          }
          if (event.getType() == RemoteRxEvent.Type.next){
                      logger.debug("WRITE request for RemoteRxEvent: next");
            buf.writeByte(1);
            buf.writeBytes(event.getData());
            super.write(ctx, buf, promise);
          }else if (event.getType() == RemoteRxEvent.Type.error){
                      logger.debug("WRITE request for RemoteRxEvent: error");
            buf.writeByte(2);
            buf.writeBytes(event.getData());
            super.write(ctx, buf, promise);
          }else if (event.getType() == RemoteRxEvent.Type.completed){
                      logger.debug("WRITE request for RemoteRxEvent: completed");
            buf.writeByte(3);
            super.write(ctx, buf, promise);
            super.flush(ctx); // TODO why do I need to explicitly call flush for this to work??? empty data??
          }else if (event.getType() == RemoteRxEvent.Type.subscribed){
                      logger.debug("WRITE request for RemoteRxEvent: subscribed");
            buf.writeByte(4);
            Map<String,String> subscribeParameters = event.getSubscribeParameters();
            if (subscribeParameters != null && !subscribeParameters.isEmpty()){
              byte[] subscribeBytes = fromMapToBytes(subscribeParameters);
              buf.writeInt(subscribeBytes.length); // write int for length
              buf.writeBytes(subscribeBytes); // write data
            }else{
              buf.writeInt(0); // no data
            }
            super.write(ctx, buf, promise);
            super.flush(ctx);
          }else if (event.getType() == RemoteRxEvent.Type.unsubscribed){
                      logger.debug("WRITE request for RemoteRxEvent: unsubscribed");
            buf.writeByte(5);
            super.write(ctx, buf, promise);
            super.flush(ctx); // TODO why do I need to explicitly call flush for this to work??? empty data??
          }
        }else{
          super.write(ctx, msg, promise);
        }
      }
     
    });
   
  }
 
  @SuppressWarnings("unchecked")
  static Map<String,String> fromBytesToMap(byte[] bytes){
    Map<String,String> map = null;
    ByteArrayInputStream bis = null;
    ObjectInput in = null;
    try{
      bis = new ByteArrayInputStream(bytes);
      in = new ObjectInputStream(bis);
      map = (Map<String,String>) in.readObject();
     
    }catch(IOException e){
      throw new RuntimeException(e);
    }catch(ClassNotFoundException e1){
      throw new RuntimeException(e1);
    }finally{
      try {
        if (bis != null){bis.close();}
        if (in != null){in.close();}
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
    return map;
  }
 
  static byte[] fromMapToBytes(Map<String,String> map){
    ByteArrayOutputStream baos = null;
    ObjectOutput out = null;
    try{
      baos = new ByteArrayOutputStream();
      out = new ObjectOutputStream(baos);  
      out.writeObject(map);
    }catch(IOException e){
      throw new RuntimeException(e);
    }finally{
      try{
        if (out != null){out.close();}
        if (baos != null){baos.close();}
      }catch(IOException e1){
        e1.printStackTrace();
        throw new RuntimeException(e1);
      }
    }
    return baos.toByteArray();
  }
 
}
TOP

Related Classes of io.reactivex.netty.RxEventPipelineConfigurator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.